diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 363f109d..503bed1f 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -385,6 +385,13 @@ static inline char peek(JSON_ParserState *state) static void cursor_position(JSON_ParserState *state, long *line_out, long *column_out) { + JSON_ASSERT(state->cursor <= state->end); + + // Redundant but helpful for hardening + if (RB_UNLIKELY(state->cursor > state->end)) { + state->cursor = state->end; + } + const char *cursor = state->cursor; long column = 0; long line = 1; @@ -1022,6 +1029,13 @@ ALWAYS_INLINE(static) bool string_scan(JSON_ParserState *state) } state->cursor++; } + + // If the string ended with an unterminated escape sequence, we might + // have gone past the end. + if (RB_UNLIKELY(state->cursor > state->end)) { + state->cursor = state->end; + } + return false; } diff --git a/test/json/json_parser_test.rb b/test/json/json_parser_test.rb index 1969e79b..292ca1a6 100644 --- a/test/json/json_parser_test.rb +++ b/test/json/json_parser_test.rb @@ -545,22 +545,26 @@ def test_nesting end def test_backslash + assert_raise(JSON::ParserError) do + JSON.parse('"\\') + end + data = [ '\\.(?i:gif|jpe?g|png)$' ] json = '["\\\\.(?i:gif|jpe?g|png)$"]' assert_equal data, parse(json) - # + data = [ '\\"' ] json = '["\\\\\""]' assert_equal data, parse(json) - # + json = '["/"]' data = [ '/' ] assert_equal data, parse(json) - # + json = '["\""]' data = ['"'] assert_equal data, parse(json) - # + json = '["\\/"]' data = ["/"] assert_equal data, parse(json)