Skip to content

Commit 2bc976d

Browse files
committed
contextjson: Fix crash
1 parent e8427b7 commit 2bc976d

2 files changed

Lines changed: 121 additions & 37 deletions

File tree

common/json/internal/contextjson/context_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,102 @@ func TestTrailingCommaToken(t *testing.T) {
292292
}
293293
}
294294

295+
func TestTokenMoreAfterCommaAcrossRefill(t *testing.T) {
296+
t.Parallel()
297+
// Positions the comma at decoder buffer offset 500 and the next value
298+
// beyond the initial 512-byte read.
299+
value := strings.Repeat("a", 497)
300+
decoder := json.NewDecoder(strings.NewReader(`["` + value + `",` + strings.Repeat(" ", 11) + `2]`))
301+
token, err := decoder.Token()
302+
if err != nil {
303+
t.Fatal(err)
304+
}
305+
if token != json.Delim('[') {
306+
t.Fatalf("start token = %v", token)
307+
}
308+
if !decoder.More() {
309+
t.Fatal("expected first array value")
310+
}
311+
token, err = decoder.Token()
312+
if err != nil {
313+
t.Fatal(err)
314+
}
315+
if token != value {
316+
t.Fatalf("first value = %#v", token)
317+
}
318+
if !decoder.More() {
319+
t.Fatal("expected second array value")
320+
}
321+
token, err = decoder.Token()
322+
if err != nil {
323+
t.Fatal(err)
324+
}
325+
if token != float64(2) {
326+
t.Fatalf("second value = %#v", token)
327+
}
328+
if decoder.More() {
329+
t.Fatal("expected end of array")
330+
}
331+
token, err = decoder.Token()
332+
if err != nil {
333+
t.Fatal(err)
334+
}
335+
if token != json.Delim(']') {
336+
t.Fatalf("end token = %v", token)
337+
}
338+
}
339+
340+
func TestTrailingCommaTokenAcrossRefill(t *testing.T) {
341+
t.Parallel()
342+
value := strings.Repeat("a", 497)
343+
tests := []struct {
344+
name string
345+
suffix string
346+
}{
347+
{
348+
name: "spaces",
349+
suffix: strings.Repeat(" ", 11) + `]`,
350+
},
351+
{
352+
name: "line comment",
353+
suffix: strings.Repeat(" ", 11) + "// trailing\n]",
354+
},
355+
}
356+
for _, test := range tests {
357+
t.Run(test.name, func(t *testing.T) {
358+
t.Parallel()
359+
decoder := json.NewDecoder(strings.NewReader(`["` + value + `",` + test.suffix))
360+
token, err := decoder.Token()
361+
if err != nil {
362+
t.Fatal(err)
363+
}
364+
if token != json.Delim('[') {
365+
t.Fatalf("start token = %v", token)
366+
}
367+
if !decoder.More() {
368+
t.Fatal("expected array value")
369+
}
370+
token, err = decoder.Token()
371+
if err != nil {
372+
t.Fatal(err)
373+
}
374+
if token != value {
375+
t.Fatalf("value = %#v", token)
376+
}
377+
if decoder.More() {
378+
t.Fatal("expected trailing comma to end array")
379+
}
380+
token, err = decoder.Token()
381+
if err != nil {
382+
t.Fatal(err)
383+
}
384+
if token != json.Delim(']') {
385+
t.Fatalf("end token = %v", token)
386+
}
387+
})
388+
}
389+
}
390+
295391
func TestTrailingComma(t *testing.T) {
296392
t.Parallel()
297393
var array []int

common/json/internal/contextjson/stream.go

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -504,10 +504,7 @@ func (dec *Decoder) More() bool {
504504
return false
505505
}
506506
if c == ',' {
507-
scanp := dec.scanp
508-
dec.scanp++
509-
c, err = dec.peekNoRefill()
510-
dec.scanp = scanp
507+
c, _, err = dec.peekFrom(dec.scanp + 1)
511508
if err != nil {
512509
return false
513510
}
@@ -519,71 +516,62 @@ func (dec *Decoder) More() bool {
519516
}
520517

521518
func (dec *Decoder) peek() (byte, error) {
519+
c, scanp, err := dec.peekFrom(dec.scanp)
520+
if err != nil {
521+
return 0, err
522+
}
523+
dec.scanp = scanp
524+
return c, nil
525+
}
526+
527+
func (dec *Decoder) peekFrom(scanp int) (byte, int, error) {
522528
var err error
523529
for {
524530
Buffer:
525-
for i := dec.scanp; i < len(dec.buf); {
526-
c := dec.buf[i]
531+
for scanp < len(dec.buf) {
532+
c := dec.buf[scanp]
527533
if isSpace(c) {
528-
i++
534+
scanp++
529535
continue
530536
}
531537
if c == '#' {
532-
next, ok := dec.skipLineCommentInBuffer(i + 1)
538+
next, ok := dec.skipLineCommentInBuffer(scanp + 1)
533539
if !ok {
534540
break
535541
}
536-
i = next
542+
scanp = next
537543
continue
538544
}
539545
if c == '/' {
540-
if i+1 >= len(dec.buf) {
546+
if scanp+1 >= len(dec.buf) {
541547
break Buffer
542548
}
543-
switch dec.buf[i+1] {
549+
switch dec.buf[scanp+1] {
544550
case '/':
545-
next, ok := dec.skipLineCommentInBuffer(i + 2)
551+
next, ok := dec.skipLineCommentInBuffer(scanp + 2)
546552
if !ok {
547553
break Buffer
548554
}
549-
i = next
555+
scanp = next
550556
continue
551557
case '*':
552-
next, ok := dec.skipBlockCommentInBuffer(i + 2)
558+
next, ok := dec.skipBlockCommentInBuffer(scanp + 2)
553559
if !ok {
554560
break Buffer
555561
}
556-
i = next
562+
scanp = next
557563
continue
558564
}
559565
}
560-
dec.scanp = i
561-
return c, nil
566+
return c, scanp, nil
562567
}
563568
// buffer has been scanned, now report any error
564569
if err != nil {
565-
return 0, err
566-
}
567-
err = dec.refill()
568-
}
569-
}
570-
571-
func (dec *Decoder) peekNoRefill() (byte, error) {
572-
var err error
573-
for {
574-
for i := dec.scanp; i < len(dec.buf); i++ {
575-
c := dec.buf[i]
576-
if isSpace(c) {
577-
continue
578-
}
579-
dec.scanp = i
580-
return c, nil
581-
}
582-
// buffer has been scanned, now report any error
583-
if err != nil {
584-
return 0, err
570+
return 0, 0, err
585571
}
572+
oldScanp := dec.scanp
586573
err = dec.refill()
574+
scanp -= oldScanp
587575
}
588576
}
589577

0 commit comments

Comments
 (0)