Skip to content

Commit 9743702

Browse files
authored
Fix parsing deadlock (#57)
Parser will deadlock if hitting `if len(pj.containingScopeOffset) != 0` before returning, since the stream is done, but we return false. Return status and done status separately.
1 parent 68d6648 commit 9743702

File tree

3 files changed

+17
-11
lines changed

3 files changed

+17
-11
lines changed

parse_json_amd64.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,14 @@ func (pj *internalParsedJson) parseMessage(msg []byte, ndjson bool) (err error)
7777
wg.Add(1)
7878
go func() {
7979
defer wg.Done()
80-
if !pj.unifiedMachine() {
80+
if ok, done := pj.unifiedMachine(); !ok {
8181
err = errors.New("Bad parsing while executing stage 2")
8282
// Keep consuming...
83-
for idx := range pj.indexChans {
84-
if idx.index == -1 {
85-
break
83+
if !done {
84+
for idx := range pj.indexChans {
85+
if idx.index == -1 {
86+
break
87+
}
8688
}
8789
}
8890
}
@@ -101,7 +103,7 @@ func (pj *internalParsedJson) parseMessage(msg []byte, ndjson bool) (err error)
101103
}
102104
return errors.New("Failed to find all structural indices for stage 1")
103105
}
104-
if !pj.unifiedMachine() {
106+
if ok, _ := pj.unifiedMachine(); !ok {
105107
// drain the channel until empty
106108
for {
107109
select {

parse_json_amd64_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,26 +637,31 @@ func benchmarkParseNumber(b *testing.B, neg int) {
637637
}
638638

639639
func BenchmarkParseNumberFloat(b *testing.B) {
640+
b.SetBytes(1)
640641
for i := 0; i < b.N; i++ {
641642
parseNumber([]byte("339.7784:"))
642643
}
643644
}
644645

645646
func BenchmarkParseAtof64FloatGolang(b *testing.B) {
647+
b.SetBytes(1)
646648
for i := 0; i < b.N; i++ {
647649
strconv.ParseFloat("339.7784", 64)
648650
}
649651
}
650652

651653
func BenchmarkParseNumberFloatExp(b *testing.B) {
654+
b.SetBytes(1)
652655
for i := 0; i < b.N; i++ {
653656
parseNumber([]byte("-5.09e75:"))
654657
}
655658
}
656659

657660
func BenchmarkParseNumberBig(b *testing.B) {
661+
b.SetBytes(1)
662+
x := []byte("123456789123456789123456789:")
658663
for i := 0; i < b.N; i++ {
659-
parseNumber([]byte("123456789123456789123456789:"))
664+
parseNumber(x)
660665
}
661666
}
662667

stage2_build_tape_amd64.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,10 @@ func isValidNullAtom(buf []byte) bool {
157157
return false
158158
}
159159

160-
func (pj *internalParsedJson) unifiedMachine() bool {
160+
func (pj *internalParsedJson) unifiedMachine() (ok, done bool) {
161161
buf := pj.Message
162162
const addOneForRoot = 1
163163

164-
done := false
165164
idx := ^uint64(0) // location of the structural character in the input (buf)
166165
offset := uint64(0) // used to contain last element of containing_scope_offset
167166

@@ -433,17 +432,17 @@ succeed:
433432

434433
// Sanity checks
435434
if len(pj.containingScopeOffset) != 0 {
436-
return false
435+
return false, done
437436
}
438437

439438
pj.annotate_previousloc(offset>>retAddressShift, pj.get_current_loc()+addOneForRoot)
440439
pj.write_tape(offset>>retAddressShift, 'r') // r is root
441440

442441
pj.isvalid = true
443-
return true
442+
return true, done
444443

445444
fail:
446-
return false
445+
return false, done
447446
}
448447

449448
// structural chars here are

0 commit comments

Comments
 (0)