Skip to content

Commit

Permalink
fix: added buffer size check when decoding key
Browse files Browse the repository at this point in the history
fix #429
  • Loading branch information
orisano committed Feb 22, 2023
1 parent a2149a5 commit cdbc292
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 16 deletions.
15 changes: 15 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4015,3 +4015,18 @@ func TestIssue408(t *testing.T) {
t.Fatal(err)
}
}

func TestIssue429(t *testing.T) {
var x struct {
N int32
}
for _, b := range []string{
`{"\u"`,
`{"\u0"`,
`{"\u00"`,
} {
if err := json.Unmarshal([]byte(b), &x); err == nil {
t.Errorf("unexpected success")
}
}
}
42 changes: 26 additions & 16 deletions internal/decoder/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,49 +158,53 @@ func (d *structDecoder) tryOptimize() {
}

// decode from '\uXXXX'
func decodeKeyCharByUnicodeRune(buf []byte, cursor int64) ([]byte, int64) {
func decodeKeyCharByUnicodeRune(buf []byte, cursor int64) ([]byte, int64, error) {
const defaultOffset = 4
const surrogateOffset = 6

if cursor+defaultOffset >= int64(len(buf)) {
return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor)
}

r := unicodeToRune(buf[cursor : cursor+defaultOffset])
if utf16.IsSurrogate(r) {
cursor += defaultOffset
if cursor+surrogateOffset >= int64(len(buf)) || buf[cursor] != '\\' || buf[cursor+1] != 'u' {
return []byte(string(unicode.ReplacementChar)), cursor + defaultOffset - 1
return []byte(string(unicode.ReplacementChar)), cursor + defaultOffset - 1, nil
}
cursor += 2
r2 := unicodeToRune(buf[cursor : cursor+defaultOffset])
if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar {
return []byte(string(r)), cursor + defaultOffset - 1
return []byte(string(r)), cursor + defaultOffset - 1, nil
}
}
return []byte(string(r)), cursor + defaultOffset - 1
return []byte(string(r)), cursor + defaultOffset - 1, nil
}

func decodeKeyCharByEscapedChar(buf []byte, cursor int64) ([]byte, int64) {
func decodeKeyCharByEscapedChar(buf []byte, cursor int64) ([]byte, int64, error) {
c := buf[cursor]
cursor++
switch c {
case '"':
return []byte{'"'}, cursor
return []byte{'"'}, cursor, nil
case '\\':
return []byte{'\\'}, cursor
return []byte{'\\'}, cursor, nil
case '/':
return []byte{'/'}, cursor
return []byte{'/'}, cursor, nil
case 'b':
return []byte{'\b'}, cursor
return []byte{'\b'}, cursor, nil
case 'f':
return []byte{'\f'}, cursor
return []byte{'\f'}, cursor, nil
case 'n':
return []byte{'\n'}, cursor
return []byte{'\n'}, cursor, nil
case 'r':
return []byte{'\r'}, cursor
return []byte{'\r'}, cursor, nil
case 't':
return []byte{'\t'}, cursor
return []byte{'\t'}, cursor, nil
case 'u':
return decodeKeyCharByUnicodeRune(buf, cursor)
}
return nil, cursor
return nil, cursor, nil
}

func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldSet, error) {
Expand Down Expand Up @@ -242,7 +246,10 @@ func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64,
return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor)
case '\\':
cursor++
chars, nextCursor := decodeKeyCharByEscapedChar(buf, cursor)
chars, nextCursor, err := decodeKeyCharByEscapedChar(buf, cursor)
if err != nil {
return 0, nil, err
}
for _, c := range chars {
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
if curBit == 0 {
Expand Down Expand Up @@ -305,7 +312,10 @@ func decodeKeyByBitmapUint16(d *structDecoder, buf []byte, cursor int64) (int64,
return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor)
case '\\':
cursor++
chars, nextCursor := decodeKeyCharByEscapedChar(buf, cursor)
chars, nextCursor, err := decodeKeyCharByEscapedChar(buf, cursor)
if err != nil {
return 0, nil, err
}
for _, c := range chars {
curBit &= bitmap[keyIdx][largeToSmallTable[c]]
if curBit == 0 {
Expand Down

0 comments on commit cdbc292

Please sign in to comment.