[ruby/json] Fix: generate_json_float to reserve enough memory for large negative...
authorJean Boussier <[email protected]>
Fri, 23 May 2025 07:28:56 +0000 (23 09:28 +0200)
committerHiroshi SHIBATA <[email protected]>
Mon, 26 May 2025 02:46:12 +0000 (26 11:46 +0900)
Fix: https://github.com/ruby/json/issues/807

Since https://github.com/ruby/json/pull/800, `fpconv_dtoa` can actually
generate up to 28 chars.

https://github.com/ruby/json/commit/d73ae93d3c

ext/json/generator/generator.c
ext/json/vendor/fpconv.c
test/json/json_generator_test.rb

index 06ab801..e67351f 100644 (file)
@@ -1406,10 +1406,9 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
     }
 
     /* This implementation writes directly into the buffer. We reserve
-     * the 24 characters that fpconv_dtoa states as its maximum, plus
-     * 2 more characters for the potential ".0" suffix.
+     * the 28 characters that fpconv_dtoa states as its maximum.
      */
-    fbuffer_inc_capa(buffer, 26);
+    fbuffer_inc_capa(buffer, 28);
     char* d = buffer->ptr + buffer->len;
     int len = fpconv_dtoa(value, d);
 
index 1bbca28..75efd46 100644 (file)
@@ -432,8 +432,8 @@ static int filter_special(double fp, char* dest)
  *
  * Input:
  * fp -> the double to convert, dest -> destination buffer.
- * The generated string will never be longer than 24 characters.
- * Make sure to pass a pointer to at least 24 bytes of memory.
+ * The generated string will never be longer than 28 characters.
+ * Make sure to pass a pointer to at least 28 bytes of memory.
  * The emitted string will not be null terminated.
  *
  * Output:
@@ -443,7 +443,7 @@ static int filter_special(double fp, char* dest)
  *
  * void print(double d)
  * {
- *      char buf[24 + 1] // plus null terminator
+ *      char buf[28 + 1] // plus null terminator
  *      int str_len = fpconv_dtoa(d, buf);
  *
  *      buf[str_len] = '\0';
@@ -451,7 +451,7 @@ static int filter_special(double fp, char* dest)
  * }
  *
  */
-static int fpconv_dtoa(double d, char dest[24])
+static int fpconv_dtoa(double d, char dest[28])
 {
     char digits[18];
 
index f869e43..914b3f4 100755 (executable)
@@ -795,6 +795,11 @@ class JSONGeneratorTest < Test::Unit::TestCase
         expecteds << "1746861937.7842371"
       end
 
+      if RUBY_ENGINE == "ruby"
+        values << -2.2471348024634545e-08 << -2.2471348024634545e-09 << -2.2471348024634545e-10
+        expecteds << "-0.000000022471348024634545" << "-0.0000000022471348024634545" << "-2.2471348024634546e-10"
+      end
+
       values.zip(expecteds).each do |value, expected|
         assert_equal expected, value.to_json
       end