commit f704c7cd828d23406319acbae58086dfb940810a from: Georgiy Belyanin via: Alexander Turenko date: Thu Aug 01 13:54:29 2024 UTC 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) commit - 07f5791b90e865ea0b19f07d2d3746ddd41ded3f commit + f704c7cd828d23406319acbae58086dfb940810a blob - /dev/null blob + 4901695fb28ff1bc6f400f3c17efaac636593d44 (mode 644) --- /dev/null +++ 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). blob - 0a99d420fdf28e113fcbdf2ac75f4d266dd9f1d9 blob + 2b808a5c98f67a7562d920e6c3f5fe149599bd3f --- test/app-tap/lua/serializer_test.lua +++ 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) blob - ed0fca40ae81538d8542f48af22596cbe5d3c129 blob + 3d3249d0c8f0c4f78239ca5ca68986b7726334c3 --- third_party/lua-yaml/lyaml.cc +++ third_party/lua-yaml/lyaml.cc @@ -155,7 +155,55 @@ yaml_is_null(const char *str, size_t len) if (len == 1 && str[0] == '~') return true; if (len == 4 && memcmp(str, "null", 4) == 0) + return true; + 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; } @@ -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.