Skip to content

Commit 65549ac

Browse files
byrootmame
andcommitted
ResumableParser#parse: don't swallow other parsers errors
Fix: #1024 (comment) Co-Authored-By: Yusuke Endoh <mame@ruby-lang.org>
1 parent 82b6b21 commit 65549ac

2 files changed

Lines changed: 31 additions & 18 deletions

File tree

ext/json/ext/parser/parser.c

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -660,13 +660,13 @@ static VALUE build_parse_error_message(const char *format, JSON_ParserState *sta
660660
return message;
661661
}
662662

663-
static VALUE parse_error_new(VALUE message, long line, long column, bool eos)
663+
static VALUE parse_error_new(JSON_ParserState *state, VALUE message, long line, long column, bool eos)
664664
{
665665
VALUE exc = rb_exc_new_str(eParserError, message);
666666
rb_ivar_set(exc, i_at_line, LONG2NUM(line));
667667
rb_ivar_set(exc, i_at_column, LONG2NUM(column));
668-
if (eos) {
669-
rb_ivar_set(exc, i_at_eos, Qtrue);
668+
if (eos && state->value_stack_handle) {
669+
rb_ivar_set(exc, i_at_eos, *state->value_stack_handle);
670670
}
671671
return exc;
672672
}
@@ -676,7 +676,7 @@ NORETURN(static) void raise_parse_error(const char *format, JSON_ParserState *st
676676
long line, column;
677677
cursor_position(state, &line, &column);
678678
VALUE message = build_parse_error_message(format, state, line, column);
679-
rb_exc_raise(parse_error_new(message, line, column, eos));
679+
rb_exc_raise(parse_error_new(state, message, line, column, eos));
680680
}
681681

682682
NORETURN(static) void raise_eos_error(const char *format, JSON_ParserState *state)
@@ -1169,7 +1169,7 @@ NORETURN(static) void raise_duplicate_key_error(JSON_ParserState *state, VALUE d
11691169
long line, column;
11701170
cursor_position(state, &line, &column);
11711171
rb_str_concat(message, build_parse_error_message("", state, line, column)) ;
1172-
rb_exc_raise(parse_error_new(message, line, column, false));
1172+
rb_exc_raise(parse_error_new(state, message, line, column, false));
11731173
}
11741174

11751175
NOINLINE(static) void json_on_duplicate_key(JSON_ParserState *state, JSON_ParserConfig *config, size_t count, const VALUE *pairs)
@@ -2281,7 +2281,7 @@ static VALUE cResumableParser_initialize(int argc, VALUE *argv, VALUE self)
22812281
return self;
22822282
}
22832283

2284-
static JSON_ResumableParser *ResumableParser_acquire(VALUE self, bool lock);
2284+
static JSON_ResumableParser *ResumableParser_acquire(VALUE *self, bool lock);
22852285

22862286
/*
22872287
* call-seq: self << string -> self
@@ -2292,7 +2292,7 @@ static VALUE cResumableParser_feed(VALUE self, VALUE str)
22922292
{
22932293
rb_check_frozen(self);
22942294

2295-
JSON_ResumableParser *parser = ResumableParser_acquire(self, false);
2295+
JSON_ResumableParser *parser = ResumableParser_acquire(&self, false);
22962296

22972297
str = convert_encoding(str);
22982298
if (!RSTRING_LEN(str)) {
@@ -2350,9 +2350,9 @@ static VALUE json_parse_any_resumable_safe(VALUE _args)
23502350
return (VALUE)json_parse_any(args->state, args->config, true);
23512351
}
23522352

2353-
static JSON_ResumableParser *ResumableParser_acquire(VALUE self, bool lock)
2353+
static JSON_ResumableParser *ResumableParser_acquire(VALUE *self, bool lock)
23542354
{
2355-
JSON_ResumableParser *parser = cResumableParser_get(self);
2355+
JSON_ResumableParser *parser = cResumableParser_get(*self);
23562356

23572357
if (parser->in_use) {
23582358
rb_raise(rb_eArgError, "ResumableParser can't be used recursively");
@@ -2365,8 +2365,8 @@ static JSON_ResumableParser *ResumableParser_acquire(VALUE self, bool lock)
23652365
// self may have moved, so we need to update all pointers
23662366
// Investigate: We might be better off keeping JSON_ParserState on the stack
23672367
// and only persist what we need.
2368-
parser->state.value_stack_handle = &self;
2369-
parser->state.frame_stack_handle = &self;
2368+
parser->state.value_stack_handle = self;
2369+
parser->state.frame_stack_handle = self;
23702370
parser->state.value_stack = &parser->value_stack;
23712371
parser->state.frames = &parser->frames;
23722372

@@ -2385,7 +2385,7 @@ static JSON_ResumableParser *ResumableParser_acquire(VALUE self, bool lock)
23852385
*/
23862386
static VALUE cResumableParser_parse(VALUE self)
23872387
{
2388-
JSON_ResumableParser *parser = ResumableParser_acquire(self, true);
2388+
JSON_ResumableParser *parser = ResumableParser_acquire(&self, true);
23892389
if (!parser->buffer) {
23902390
parser->in_use = false;
23912391
return Qfalse;
@@ -2419,8 +2419,9 @@ static VALUE cResumableParser_parse(VALUE self)
24192419
parser->in_use = false;
24202420
if (status) {
24212421
complete = false;
2422-
if (RTEST(rb_ivar_get(rb_errinfo(), rb_intern("@eos")))) {
2423-
complete = false; // is an EOS error
2422+
VALUE error_source = rb_ivar_get(rb_errinfo(), i_at_eos);
2423+
if (error_source == self) {
2424+
complete = false; // is an EOS error raised by ourself
24242425
rb_set_errinfo(Qnil);
24252426
} else {
24262427
rb_jump_tag(status); // reraise
@@ -2437,7 +2438,7 @@ static VALUE cResumableParser_parse(VALUE self)
24372438
*/
24382439
static VALUE cResumableParser_value_p(VALUE self)
24392440
{
2440-
JSON_ResumableParser *parser = ResumableParser_acquire(self, false);
2441+
JSON_ResumableParser *parser = ResumableParser_acquire(&self, false);
24412442

24422443
if (parser->value_stack.head > 0) {
24432444
json_frame *frame = json_frame_stack_peek(&parser->frames);
@@ -2461,7 +2462,7 @@ static VALUE cResumableParser_value_p(VALUE self)
24612462
*/
24622463
static VALUE cResumableParser_value(VALUE self)
24632464
{
2464-
JSON_ResumableParser *parser = ResumableParser_acquire(self, false);
2465+
JSON_ResumableParser *parser = ResumableParser_acquire(&self, false);
24652466

24662467
if (parser->frames.head > 0) {
24672468
json_frame *frame = json_frame_stack_peek(&parser->frames);
@@ -2483,7 +2484,7 @@ static VALUE cResumableParser_value(VALUE self)
24832484
*/
24842485
static VALUE cResumableParser_clear(VALUE self)
24852486
{
2486-
JSON_ResumableParser *parser = ResumableParser_acquire(self, false);
2487+
JSON_ResumableParser *parser = ResumableParser_acquire(&self, false);
24872488
parser->buffer = 0;
24882489
parser->frames.head = 0;
24892490
parser->value_stack.head = 0;
@@ -2575,7 +2576,7 @@ static VALUE cResumableParser_partial_value_body(VALUE self)
25752576
*/
25762577
static VALUE cResumableParser_partial_value(VALUE self)
25772578
{
2578-
JSON_ResumableParser *parser = ResumableParser_acquire(self, true);
2579+
JSON_ResumableParser *parser = ResumableParser_acquire(&self, true);
25792580

25802581
int status;
25812582
VALUE result = rb_protect(cResumableParser_partial_value_body, self, &status);

test/json/resumable_parser_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ def test_clear_resets_nesting_depth
7777
assert_equal [1], parser.value
7878
end
7979

80+
def test_nested_parse_error
81+
parser = new_parser(on_load: ->(o) do
82+
JSON.parse("") #=> raises JSON::ParserError
83+
o
84+
end)
85+
parser << "[1]"
86+
87+
assert_raise(JSON::ParserError) do
88+
parser.parse
89+
end
90+
end
91+
8092
def test_parse_document_direct
8193
@parser << '[true]'
8294
assert_equal true, @parser.parse

0 commit comments

Comments
 (0)