diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index b67feacb..e4f140d7 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -2274,6 +2274,8 @@ static VALUE cResumableParser_initialize(int argc, VALUE *argv, VALUE self) return self; } +static JSON_ResumableParser *ResumableParser_acquire(VALUE self, bool lock); + /* * call-seq: self << string -> self * @@ -2282,13 +2284,14 @@ static VALUE cResumableParser_initialize(int argc, VALUE *argv, VALUE self) static VALUE cResumableParser_feed(VALUE self, VALUE str) { rb_check_frozen(self); + + JSON_ResumableParser *parser = ResumableParser_acquire(self, false); + str = convert_encoding(str); if (!RSTRING_LEN(str)) { return self; } - JSON_ResumableParser *parser = cResumableParser_get(self); - size_t offset = parser->state.cursor - parser->state.start; const size_t remaining = parser->state.end - parser->state.cursor; diff --git a/test/json/resumable_parser_test.rb b/test/json/resumable_parser_test.rb index 329bbc34..40dcb4a4 100644 --- a/test/json/resumable_parser_test.rb +++ b/test/json/resumable_parser_test.rb @@ -243,6 +243,26 @@ def test_reentrency_prevented_in_partial_value refute_predicate parser, :value? end + def test_feed_during_callback_prevented + parser = nil + callback = ->(o) do + parser << '99' if o == 1 # feeding while a parse is running must be rejected + o + end + parser = new_parser(on_load: callback) + parser << '[1, 2, 3]' + error = assert_raise ArgumentError do + parser.parse + end + assert_equal "ResumableParser can't be used recursively", error.message + + # the lock is released, so the parser stays usable + parser = new_parser + parser << '[1, 2, 3]' + assert parser.parse + assert_equal [1, 2, 3], parser.value + end + def test_exception_unlock_parser called = false parser = nil