Skip to content

Commit

Permalink
fix: In decodeUnicode, the case that the expected buffer's state is n…
Browse files Browse the repository at this point in the history
…ot satisfied after reading.

fix #374
  • Loading branch information
orisano committed Jul 6, 2022
1 parent 1468eef commit d4308f9
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 9 deletions.
15 changes: 15 additions & 0 deletions encode_test.go
Expand Up @@ -7,12 +7,14 @@ import (
stdjson "encoding/json"
"errors"
"fmt"
"io"
"log"
"math"
"math/big"
"reflect"
"regexp"
"strconv"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -2424,3 +2426,16 @@ func TestIssue376(t *testing.T) {
t.Errorf("unexpected result: %v != %v", got, expected)
}
}

func TestIssue374(t *testing.T) {
r := io.MultiReader(strings.NewReader(strings.Repeat(" ", 505)+`"\u`), strings.NewReader(`0000"`))
var v interface{}
if err := json.NewDecoder(r).Decode(&v); err != nil {
t.Fatal(err)
}
got := v.(string)
expected := "\u0000"
if got != expected {
t.Errorf("unexpected result: %q != %q", got, expected)
}
}
25 changes: 16 additions & 9 deletions internal/decoder/string.go
Expand Up @@ -95,24 +95,31 @@ func unicodeToRune(code []byte) rune {
return r
}

func readAtLeast(s *Stream, n int64) bool {
for s.cursor+n >= s.length {
if !s.read() {
return false
}
}
return true
}

func decodeUnicodeRune(s *Stream, p unsafe.Pointer) (rune, int64, unsafe.Pointer, error) {
const defaultOffset = 5
const surrogateOffset = 11

if s.cursor+defaultOffset >= s.length {
if !s.read() {
return rune(0), 0, nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset())
}
p = s.bufptr()
if !readAtLeast(s, defaultOffset) {
return rune(0), 0, nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset())
}
p = s.bufptr()

r := unicodeToRune(s.buf[s.cursor+1 : s.cursor+defaultOffset])
if utf16.IsSurrogate(r) {
if s.cursor+surrogateOffset >= s.length {
s.read()
p = s.bufptr()
if !readAtLeast(s, surrogateOffset) {
return unicode.ReplacementChar, defaultOffset, s.bufptr(), nil
}
if s.cursor+surrogateOffset >= s.length || s.buf[s.cursor+defaultOffset] != '\\' || s.buf[s.cursor+defaultOffset+1] != 'u' {
p = s.bufptr()
if s.buf[s.cursor+defaultOffset] != '\\' || s.buf[s.cursor+defaultOffset+1] != 'u' {
return unicode.ReplacementChar, defaultOffset, p, nil
}
r2 := unicodeToRune(s.buf[s.cursor+defaultOffset+2 : s.cursor+surrogateOffset])
Expand Down

0 comments on commit d4308f9

Please sign in to comment.