summary refs log tree commit
diff options
context:
space:
mode:
-rw-r--r--ext/json/ext/generator/generator.c16
-rw-r--r--ext/json/ext/generator/generator.h2
-rwxr-xr-xtests/test_json_generate.rb13
3 files changed, 26 insertions, 5 deletions
diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c
index 4e44178..a75118a 100644
--- a/ext/json/ext/generator/generator.c
+++ b/ext/json/ext/generator/generator.c
@@ -349,6 +349,16 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
     }
 }
 
+static void fbuffer_append_str(FBuffer *fb, VALUE str)
+{
+    const char *newstr = RSTRING_PTR(str);
+    unsigned long len = RSTRING_LEN(str);
+
+    RB_GC_GUARD(str);
+
+    fbuffer_append(fb, newstr, len);
+}
+
 static void fbuffer_append_char(FBuffer *fb, char newchr)
 {
     fbuffer_inc_capa(fb, 1);
@@ -852,7 +862,7 @@ static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
 static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
 {
     VALUE tmp = rb_funcall(obj, i_to_s, 0);
-    fbuffer_append(buffer, RSTRING_PAIR(tmp));
+    fbuffer_append_str(buffer, tmp);
 }
 
 static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
@@ -869,7 +879,7 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
             rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp));
         }
     }
-    fbuffer_append(buffer, RSTRING_PAIR(tmp));
+    fbuffer_append_str(buffer, tmp);
 }
 
 static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
@@ -897,7 +907,7 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
     } else if (rb_respond_to(obj, i_to_json)) {
         tmp = rb_funcall(obj, i_to_json, 1, Vstate);
         Check_Type(tmp, T_STRING);
-        fbuffer_append(buffer, RSTRING_PAIR(tmp));
+        fbuffer_append_str(buffer, tmp);
     } else {
         tmp = rb_funcall(obj, i_to_s, 0);
         Check_Type(tmp, T_STRING);
diff --git a/ext/json/ext/generator/generator.h b/ext/json/ext/generator/generator.h
index ee496fe..2a83149 100644
--- a/ext/json/ext/generator/generator.h
+++ b/ext/json/ext/generator/generator.h
@@ -45,8 +45,6 @@
 #define RSTRING_LEN(string) RSTRING(string)->len
 #endif
 
-#define RSTRING_PAIR(string) RSTRING_PTR(string), RSTRING_LEN(string)
-
 /* fbuffer implementation */
 
 typedef struct FBufferStruct {
diff --git a/tests/test_json_generate.rb b/tests/test_json_generate.rb
index 9b0cff4..bc4e395 100755
--- a/tests/test_json_generate.rb
+++ b/tests/test_json_generate.rb
@@ -177,4 +177,17 @@ EOT
     assert_raises(JSON::NestingError) { ary.to_json(s) }
     assert_equal 19, s.depth
   end
+
+  def test_gc
+    bignum_too_long_to_embed_as_string = 1234567890123456789012345
+    expect = bignum_too_long_to_embed_as_string.to_s
+    stress, GC.stress = GC.stress, true
+
+    10.times do |i|
+      tmp = bignum_too_long_to_embed_as_string.to_json
+      assert_equal expect, tmp
+    end
+    ensure
+      GC.stress = stress
+  end if GC.respond_to?(:stress=)
 end