From 5686cef825626d42e92f11dd73a0512b554495c0 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Fri, 19 Jun 2026 02:44:26 +0900 Subject: [PATCH] Fix off-by-one line number in parse error messages cursor_position consumed the newline ending the previous line (post-decrement) before counting lines, so any error past the first line was reported one line too low (e.g. "[1,\n@" reported '@' at line 1 instead of line 2). Count that newline when the column loop breaks on it. Co-Authored-By: Jean Boussier --- ext/json/ext/parser/parser.c | 1 + test/json/json_parser_test.rb | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 136aab6a..5aedae48 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -593,6 +593,7 @@ static void cursor_position(JSON_ParserState *state, long *line_out, long *colum while (cursor >= state->start) { if (*cursor-- == '\n') { + line++; break; } column++; diff --git a/test/json/json_parser_test.rb b/test/json/json_parser_test.rb index c1aa2f61..c891dd7c 100644 --- a/test/json/json_parser_test.rb +++ b/test/json/json_parser_test.rb @@ -862,7 +862,7 @@ def test_parse_error_incomplete_hash end def test_parse_error_snippet - omit "C ext only test" unless RUBY_ENGINE == "ruby" + omit "JRuby errors don't contain positions" unless RUBY_ENGINE == "ruby" error = assert_raise(JSON::ParserError) { JSON.parse("あああああああああああああああああああああああ") } assert_equal "unexpected character: 'ああああああああああ' at line 1 column 1", error.message @@ -875,6 +875,15 @@ def test_parse_error_snippet error = assert_raise(JSON::ParserError) { JSON.parse("abcあああああああああああああああああああああああ") } assert_equal "unexpected character: 'abcあああああああああ' at line 1 column 1", error.message + + error = assert_raise(JSON::ParserError) { JSON.parse("[1,\n@") } + assert_equal "unexpected character: '@' at line 2 column 1", error.message + + error = assert_raise(JSON::ParserError) { JSON.parse("[\n 1,\n @\n]") } + assert_equal "unexpected character: '@' at line 3 column 3", error.message + + error = assert_raise(JSON::ParserError) { JSON.parse("@") } + assert_equal "unexpected character: '@' at line 1 column 1", error.message end def test_parse_leading_slash