Commit Diff


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.