Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions ext/json/ext/parser/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -631,17 +631,15 @@ static VALUE build_parse_error_message(const char *format, JSON_ParserState *sta
}

if (len) {
buffer[0] = '\'';
MEMCPY(buffer + 1, ptr, char, len);

while (buffer[len] >= 0x80 && buffer[len] < 0xC0) { // Is continuation byte
len--;
}

if (buffer[len] >= 0xC0) { // multibyte character start
len--;
if (len == PARSE_ERROR_FRAGMENT_LEN) {
// Only trim when the byte limit splits a multibyte character.
while (len && (unsigned char)ptr[len] >= 0x80 && (unsigned char)ptr[len] < 0xC0) {
len--;
}
}

buffer[0] = '\'';
MEMCPY(buffer + 1, ptr, char, len);
buffer[len + 1] = '\'';
buffer[len + 2] = '\0';
ptr = (const char *)buffer;
Expand Down
27 changes: 26 additions & 1 deletion test/json/json_parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ def test_parse_error_snippet
assert_equal "unexpected character: 'aああああああああああ' at line 1 column 1", error.message

error = assert_raise(JSON::ParserError) { JSON.parse("abあああああああああああああああああああああああ") }
assert_equal "unexpected character: 'abあああああああああ' at line 1 column 1", error.message
assert_equal "unexpected character: 'abああああああああああ' at line 1 column 1", error.message

error = assert_raise(JSON::ParserError) { JSON.parse("abcあああああああああああああああああああああああ") }
assert_equal "unexpected character: 'abcあああああああああ' at line 1 column 1", error.message
Expand All @@ -855,6 +855,31 @@ def test_parse_error_snippet

error = assert_raise(JSON::ParserError) { JSON.parse("@") }
assert_equal "unexpected character: '@' at line 1 column 1", error.message

error = assert_raise(JSON::ParserError) { JSON.parse('"a" 日本') }
assert_equal "unexpected token at end of stream '日本' at line 1 column 5", error.message

error = assert_raise(JSON::ParserError) { JSON.parse('[1, é') }
assert_equal "unexpected character: 'é' at line 1 column 5", error.message
end

def test_parse_error_snippet_multibyte_boundaries
omit "JRuby errors don't contain positions" if RUBY_ENGINE == "jruby"

['é', '日', '😀'].each do |char|
['', ' ', "\n", "\t", "\r"].each do |suffix|
error = assert_raise(JSON::ParserError) { JSON.parse(char + suffix) }
assert_equal "unexpected character: '#{char}' at line 1 column 1", error.message
end

(28..32).each do |padding|
prefix = 'a' * padding
fragment = prefix + char * ((32 - padding) / char.bytesize)
error = assert_raise(JSON::ParserError) { JSON.parse(prefix + char * 20) }
assert_equal "unexpected character: '#{fragment}' at line 1 column 1", error.message
assert_predicate error.message, :valid_encoding?
end
end
end

def test_parse_error_json_path
Expand Down
Loading