summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Patterson <tenderlove@ruby-lang.org>2019-10-17 13:30:09 -0700
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2019-10-31 10:39:47 +0900
commitbd1c2748cbcb5f75c8a045ba3ca12ac1b710ebdd (patch)
treebfd28f3dada7358c79f0c6fbc3aab11addd523d8
parent8d8e1aa70297d55034e3f6a4ce2f32300294b2a4 (diff)
downloadjson-bd1c2748cbcb5f75c8a045ba3ca12ac1b710ebdd.tar.gz
Look up constant instead of caching in a global
The global can go bad if the compactor runs, so we need to look up the constant instead of caching it in a global.
-rw-r--r--ext/json/ext/generator/generator.c9
-rw-r--r--tests/json_generator_test.rb37
2 files changed, 40 insertions, 6 deletions
diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c
index cc8c3a7..3ff06ad 100644
--- a/ext/json/ext/generator/generator.c
+++ b/ext/json/ext/generator/generator.c
@@ -15,7 +15,7 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
#endif
mFloat, mString, mString_Extend,
mTrueClass, mFalseClass, mNilClass, eGeneratorError,
- eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
+ eNestingError, CRegexp_MULTILINE,
i_SAFE_STATE_PROTOTYPE;
static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
@@ -1073,10 +1073,8 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
} else if (rb_obj_is_kind_of(opts, rb_cHash)) {
return rb_funcall(self, i_new, 1, opts);
} else {
- if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
- CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
- }
- return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
+ VALUE prototype = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
+ return rb_funcall(prototype, i_dup, 0);
}
}
@@ -1488,5 +1486,4 @@ void Init_generator(void)
i_encode = rb_intern("encode");
#endif
i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
- CJSON_SAFE_STATE_PROTOTYPE = Qnil;
}
diff --git a/tests/json_generator_test.rb b/tests/json_generator_test.rb
index 86be398..a85bd11 100644
--- a/tests/json_generator_test.rb
+++ b/tests/json_generator_test.rb
@@ -40,6 +40,43 @@ class JSONGeneratorTest < Test::Unit::TestCase
EOT
end
+ def silence
+ v = $VERBOSE
+ $VERBOSE = nil
+ yield
+ ensure
+ $VERBOSE = v
+ end
+
+ def test_remove_const_segv
+ stress = GC.stress
+ const = JSON::SAFE_STATE_PROTOTYPE.dup
+
+ bignum_too_long_to_embed_as_string = 1234567890123456789012345
+ expect = bignum_too_long_to_embed_as_string.to_s
+ GC.stress = true
+
+ 10.times do |i|
+ tmp = bignum_too_long_to_embed_as_string.to_json
+ raise "'\#{expect}' is expected, but '\#{tmp}'" unless tmp == expect
+ end
+
+ silence do
+ JSON.const_set :SAFE_STATE_PROTOTYPE, nil
+ end
+
+ 10.times do |i|
+ assert_raise TypeError do
+ bignum_too_long_to_embed_as_string.to_json
+ end
+ end
+ ensure
+ GC.stress = stress
+ silence do
+ JSON.const_set :SAFE_STATE_PROTOTYPE, const
+ end
+ end
+
def test_generate
json = generate(@hash)
assert_equal(parse(@json2), parse(json))