From f704c7cd828d23406319acbae58086dfb940810a Mon Sep 17 00:00:00 2001 From: Georgiy Belyanin <belyaningeorge@ya.ru> Date: Tue, 9 Jul 2024 16:16:58 +0300 Subject: [PATCH] lua-yaml: wrap large doubles in quotes Since tarantool/luajit@a16313f large exponent double strings are not considered convertible to number. It broke encoding lua objects to YAML because single quotes weren't considered necessary for decoding. This commit adds wrapping of every string containing infinite double values into a single quotes. Closes #10164 NO_DOC=bug fix (cherry picked from commit 7c3f42590240525d2e543305b6c289ddb30054a2) --- .../gh-10164-yaml-encoding-large-exps.md | 4 ++ test/app-tap/lua/serializer_test.lua | 5 +- third_party/lua-yaml/lyaml.cc | 50 ++++++++++++++++++- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/gh-10164-yaml-encoding-large-exps.md diff --git a/changelogs/unreleased/gh-10164-yaml-encoding-large-exps.md b/changelogs/unreleased/gh-10164-yaml-encoding-large-exps.md new file mode 100644 index 0000000000..4901695fb2 --- /dev/null +++ b/changelogs/unreleased/gh-10164-yaml-encoding-large-exps.md @@ -0,0 +1,4 @@ +## bugfix/lua/yaml + +* Strings with large exponential values equal to infinity are now encoded as + strings instead of numbers (gh-10164). diff --git a/test/app-tap/lua/serializer_test.lua b/test/app-tap/lua/serializer_test.lua index 0a99d420fd..2b808a5c98 100644 --- a/test/app-tap/lua/serializer_test.lua +++ b/test/app-tap/lua/serializer_test.lua @@ -236,7 +236,7 @@ local function test_boolean(test, s) end local function test_string(test, s) - test:plan(8) + test:plan(11) rt(test, s, "") rt(test, s, "abcde") rt(test, s, "Кудыкины горы") -- utf-8 @@ -245,6 +245,9 @@ local function test_string(test, s) rt(test, s, '$a\t $') rt(test, s, [[$a\t $]]) rt(test, s, [[$a\\t $]]) + rt(test, s, '9e123456789') + rt(test, s, 'infinity') + rt(test, s, 'NaN') end local function test_nil(test, s) diff --git a/third_party/lua-yaml/lyaml.cc b/third_party/lua-yaml/lyaml.cc index ed0fca40ae..3d3249d0c8 100644 --- a/third_party/lua-yaml/lyaml.cc +++ b/third_party/lua-yaml/lyaml.cc @@ -159,6 +159,54 @@ yaml_is_null(const char *str, size_t len) return false; } +/** + * Verify whether a string represents a number literal in YAML. + * + * Non-standard: + * + * False-positives: + * - 'inf', 'nan' literals despite the case are parsed as numbers + * (the standard specifies only 'inf', 'Inf', 'INF', 'nan', + * 'NaN', 'NAN'). + * - 'infinity' (ignoring case) is considered a number. + * - Binary literals ('0b...') are considered numbers. + * + * Bugs: + * - Octal numbers are not supported. + * + * This function is used only in encoding for wrapping strings + * containing number literals in quotes to make YAML parser + * handle them as strings. It means false-positives will lead to + * extra quotation marks and are not dangerous at all. + * + * @param str Literal to check. + * @param len Length of @a str. + * + * @retval Whether @a str represents a number value. + */ +static inline bool +yaml_is_number(const char *str, size_t len, struct lua_State *L) +{ + /* + * TODO: Should be implemented with the literal parser + * instead of using strtod() and lua_isnumber(). + * Using parser will make it possible to remove the third + * argument. + */ + if (len == 0) + return false; + + if (lua_isnumber(L, -1)) + return true; + + char *endptr = NULL; + fpconv_strtod(str, &endptr); + if (endptr == str + len) + return true; + + return false; +} + static void generate_error_message(struct lua_yaml_loader *loader) { char buf[256]; luaL_Buffer b; @@ -668,7 +716,7 @@ static int dump_node(struct lua_yaml_dumper *dumper) case MP_STR: str = lua_tolstring(dumper->L, -1, &len); if (yaml_is_null(str, len) || yaml_is_bool(str, len, &unused) || - lua_isnumber(dumper->L, -1)) { + yaml_is_number(str, len, dumper->L)) { /* * The string is convertible to a null, a boolean or * a number, quote it to preserve its type. -- GitLab