diff options
author | Eric Wong <normalperson@yhbt.net> | 2011-08-09 01:29:43 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2011-08-09 03:38:59 +0000 |
commit | 8a82bffe927e8928e304b9610a75ea07b0c4a798 (patch) | |
tree | 6dbdaedbe53418d271235bbb4778b44de4484224 /ext/json/ext/generator/generator.c | |
parent | f7f78896607b6f6226cdee4ae76de922d4583d32 (diff) | |
download | ruby-json-8a82bffe927e8928e304b9610a75ea07b0c4a798.tar.gz |
ext/json/generator/generator.c: prevent GC of temporary strings
We need to guard temporary strings from being collected while we append to the JSON buffer (which may allocate memory). The RSTRING_PAIR macro is dangerous since it preserves no pointer to the original string VALUE, allowing GC to reap the object while we're still using the (C) string pointer. The included test case shows data corruption with large Bignums without this fix.
Diffstat (limited to 'ext/json/ext/generator/generator.c')
-rw-r--r-- | ext/json/ext/generator/generator.c | 16 |
1 files changed, 13 insertions, 3 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); |