x.json2: fix "\\" scanner bug, disallow (ch < 0x20) unescaped control characters (#23954)

This commit is contained in:
Mr. Doge 2025-03-16 07:38:40 -04:00 committed by GitHub
parent b2ff9d5d08
commit 21874f93dc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 26 additions and 8 deletions

View file

@ -127,14 +127,18 @@ fn (mut s Scanner) text_scan() Token {
break
}
ch := s.text[s.pos]
if (s.pos - 1 >= 0 && s.text[s.pos - 1] != `\\`) && ch == `"` {
if ch == `"` {
has_closed = true
break
} else if (s.pos - 1 >= 0 && s.text[s.pos - 1] != `\\`) && ch in important_escapable_chars {
return s.error('character must be escaped with a backslash')
} else if (s.pos == s.text.len - 1 && ch == `\\`) || ch == u8(0) {
return s.error('invalid backslash escape')
} else if s.pos + 1 < s.text.len && ch == `\\` {
} else if ch in important_escapable_chars {
return s.error('character must be escaped with a backslash, replace with: \\${valid_unicode_escapes[important_escapable_chars.index(ch)]}')
} else if ch < 0x20 {
return s.error('character must be escaped with a unicode escape, replace with: \\u${ch:04x}')
} else if ch == `\\` {
if s.pos == s.text.len - 1 {
return s.error('incomplete backslash escape at end of JSON input')
}
peek := s.text[s.pos + 1]
if peek in valid_unicode_escapes {
chrs << unicode_transform_escapes[int(peek)]

View file

@ -46,7 +46,21 @@ fn test_str_invalid_must_be_escape() {
}
tok := sc.scan()
assert tok.kind == .error
assert tok.lit.bytestr() == 'character must be escaped with a backslash'
assert tok.lit.bytestr() == 'character must be escaped with a backslash, replace with: \\${valid_unicode_escapes[important_escapable_chars.index(ch)]}'
}
}
fn test_str_control_must_be_escape() {
for ch := u8(0); ch < 0x20; ch++ {
if ch in important_escapable_chars {
continue
}
mut sc := Scanner{
text: [u8(`"`), `t`, ch, `"`]
}
tok := sc.scan()
assert tok.kind == .error
assert tok.lit.bytestr() == 'character must be escaped with a unicode escape, replace with: \\u${ch:04x}'
}
}

View file

@ -6,7 +6,7 @@ fn test_raw_decode_string() {
}
fn test_raw_decode_string_escape() {
jstr := json.raw_decode('"\u001b"')!
jstr := json.raw_decode('"\\u001b"')!
str := jstr.str()
assert str.len == 1
assert str[0] == 27