From 350949bee45e4052e8305831ca64bbbaad740300 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Fri, 29 May 2026 09:05:01 +0200 Subject: [PATCH] Prevent buffer over-read when generating EOF error When reaching EOS right after an escape the cursor is one byte too far. Reported-By: Yuhang Wu --- ext/json/ext/parser/parser.c | 14 ++++++++++++++ test/json/json_parser_test.rb | 12 ++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) 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)