go-json icon indicating copy to clipboard operation
go-json copied to clipboard

"panic: runtime error: index out of range" when fuzz testing

Open Sanchous98 opened this issue 2 years ago • 4 comments

Code that generates bug:

type eventType string

func (e eventType) Error() error { return errors.New("invalid event type " + string(e)) }

const TransactionIdRsp eventType = "transactionIdRsp"

type response struct {
	ShortAddr     string          `json:"short_addr"`
	ExtAddr       string          `json:"ext_addr"`
	Rssi          int             `json:"rssi"`
	EventType     eventType       `json:"eventType"`
	Payload       json.RawMessage `json:"payload"`
	TransactionId int             `json:"transactionId"`
}

type TransactionIdResponse struct {
	DeviceTransactionId int `json:"deviceTransactionId"`
}

func (t *TransactionIdResponse) UnmarshalJSON(bytes []byte) error {
	type transactionIdResponse TransactionIdResponse

	var r response
	var err error

	if err = json.Unmarshal(bytes, &r); err != nil {
		return err
	}

	if r.EventType != TransactionIdRsp {
		return r.EventType.Error()
	}

	if err = json.Unmarshal(r.Payload, (*transactionIdResponse)(t)); err != nil {
		return err
	}

	return nil
}

Test case:

func FuzzTransactionIdResponseUnmarshal(f *testing.F) {
	f.Add(string(TransactionIdRsp), 0)

	f.Fuzz(func(t *testing.T, eT string, deviceTransactionId int) {
		value := []byte(fmt.Sprintf(`{"short_addr":"0x2","ext_addr":"0x124b001cbd4efa","rssi":-45,"eventType":"%s","payload":{"deviceTransactionId":%d},"transactionId":0}`, eT, deviceTransactionId))
		var j TransactionIdResponse
		err := json.Unmarshal(value, &j)

		if eT != string(TransactionIdRsp) {
			target := TransactionIdRsp.Error()
			require.ErrorAs(t, err, &target)
			return
		}

		require.NoError(t, err)
		assert.Equal(t, deviceTransactionId, j.DeviceTransactionId)
	})
}

All the time buggy string is smth. like string("\",\"\\0\"\\}"), but running this corpus separately doesn't produce any error. The problem appears only on fuzz testing.

Stack trace:

=== RUN   FuzzTransactionIdResponseUnmarshal
fuzz: elapsed: 0s, gathering baseline coverage: 0/257 completed
fuzz: elapsed: 1s, gathering baseline coverage: 257/257 completed, now fuzzing with 16 workers
fuzz: elapsed: 3s, execs: 183977 (61015/sec), new interesting: 1 (total: 258)
fuzz: elapsed: 6s, execs: 449113 (88654/sec), new interesting: 1 (total: 258)
fuzz: minimizing 60-byte failing input file
fuzz: elapsed: 8s, minimizing
--- FAIL: FuzzTransactionIdResponseUnmarshal (8.17s)
    --- FAIL: FuzzTransactionIdResponseUnmarshal (0.00s)
        testing.go:1485: panic: runtime error: index out of range [85] with length 83
            goroutine 39572 [running]:
            runtime/debug.Stack()
            	C:/Users/Alexander/sdk/go1.20.2/src/runtime/debug/stack.go:24 +0x9e
            testing.tRunner.func1()
            	C:/Users/Alexander/sdk/go1.20.2/src/testing/testing.go:1485 +0x1f6
            panic({0x13e26c0, 0xc0046bc2b8})
            	C:/Users/Alexander/sdk/go1.20.2/src/runtime/panic.go:884 +0x213
            github.com/goccy/go-json/internal/decoder.skipWhiteSpace(...)
            	C:/Users/Alexander/go/pkg/mod/github.com/goccy/[email protected]/internal/decoder/context.go:49
            github.com/goccy/go-json/internal/decoder.(*structDecoder).Decode(0xc000246000, 0xc003ef0120, 0x0, 0xc004944360?, 0xc00493c600)
            	C:/Users/Alexander/go/pkg/mod/github.com/goccy/[email protected]/internal/decoder/struct.go:786 +0x10d0
            github.com/goccy/go-json.unmarshal({0xc004944360?, 0x100c004389438?, 0x29fd514bd18?}, {0x139d660, 0xc00493c600}, {0x0, 0x0, 0x0?})
            	C:/Users/Alexander/go/pkg/mod/github.com/goccy/[email protected]/decode.go:47 +0x23c
            github.com/goccy/go-json.Unmarshal(...)
            	C:/Users/Alexander/go/pkg/mod/github.com/goccy/[email protected]/json.go:276
            bitbucket/4suites/4suites-fc-messages.(*response).UnmarshalJSON(0x52?, {0xc004944360?, 0x0?, 0x60?})
            	C:/Users/Alexander/GolandProjects/4suites-fc-messages/base.go:61 +0x5b
            github.com/goccy/go-json/internal/decoder.(*unmarshalJSONDecoder).Decode(0xc0002000c0, 0xc0000969e0, 0x9200000098?, 0xc0049442a0?, 0xc00493c600)
            	C:/Users/Alexander/go/pkg/mod/github.com/goccy/[email protected]/internal/decoder/unmarshal_json.go:94 +0x3d3
            github.com/goccy/go-json.unmarshal({0xc0049442a0?, 0xc00493fea0?, 0xfaab2d?}, {0x13b60c0, 0xc00493c600}, {0x0, 0x0, 0x0?})
            	C:/Users/Alexander/go/pkg/mod/github.com/goccy/[email protected]/decode.go:47 +0x23c
            github.com/goccy/go-json.Unmarshal(...)
            	C:/Users/Alexander/go/pkg/mod/github.com/goccy/[email protected]/json.go:276
            bitbucket/4suites/4suites-fc-messages.(*TransactionIdResponse).UnmarshalJSON(0x52?, {0xc0049442a0, 0x52, 0x52})
            	C:/Users/Alexander/GolandProjects/4suites-fc-messages/transaction_id.go:81 +0x9a
            github.com/goccy/go-json/internal/decoder.(*unmarshalJSONDecoder).Decode(0xc0000b7f20, 0xc000222120, 0x100c00493fe00?, 0xc00493fe00?, 0xc0048cb088)
            	C:/Users/Alexander/go/pkg/mod/github.com/goccy/[email protected]/internal/decoder/unmarshal_json.go:94 +0x3d3
            github.com/goccy/go-json.unmarshal({0xc00493fe00?, 0xc00493fd60?, 0x94?}, {0x13b5f40, 0xc0048cb088}, {0x0, 0x0, 0x0?})
            	C:/Users/Alexander/go/pkg/mod/github.com/goccy/[email protected]/decode.go:47 +0x23c
            github.com/goccy/go-json.Unmarshal(...)
            	C:/Users/Alexander/go/pkg/mod/github.com/goccy/[email protected]/json.go:276
            bitbucket/4suites/4suites-fc-messages.FuzzTransactionIdResponseUnmarshal.func1(0x0?, {0xc0048cb070, 0x10}, 0x1008419?)
            	C:/Users/Alexander/GolandProjects/4suites-fc-messages/transaction_id_test.go:72 +0x13f
            reflect.Value.call({0x13ae240?, 0x142df50?, 0xfef156?}, {0x13fb11e, 0x4}, {0xc00493c5a0, 0x3, 0x4?})
            	C:/Users/Alexander/sdk/go1.20.2/src/reflect/value.go:586 +0xb07
            reflect.Value.Call({0x13ae240?, 0x142df50?, 0x15d8df0?}, {0xc00493c5a0?, 0x13fa600?, 0xc0048cb068?})
            	C:/Users/Alexander/sdk/go1.20.2/src/reflect/value.go:370 +0xbc
            testing.(*F).Fuzz.func1.1(0x0?)
            	C:/Users/Alexander/sdk/go1.20.2/src/testing/fuzz.go:335 +0x3f3
            testing.tRunner(0xc00493b380, 0xc004940480)
            	C:/Users/Alexander/sdk/go1.20.2/src/testing/testing.go:1576 +0x10b
            created by testing.(*F).Fuzz.func1
            	C:/Users/Alexander/sdk/go1.20.2/src/testing/fuzz.go:322 +0x5b9
            
    
    Failing input written to testdata\fuzz\FuzzTransactionIdResponseUnmarshal\02d35f38fb554e01
    To re-run:
    go test -run=FuzzTransactionIdResponseUnmarshal/02d35f38fb554e01

FAIL
exit status 1
FAIL	bitbucket/4suites/4suites-fc-messages	8.208s

Sanchous98 avatar Mar 22 '23 21:03 Sanchous98

sorry, i cannot reproduce it.

orisano avatar Mar 23 '23 01:03 orisano

sorry, i cannot reproduce it.

I tried to on my PC running windows 11. It fails maximum in 40 seconds. Also I tried on my Macbook Pro 2015 running macOS 12.6.3. Iе fell in 330 seconds. Maybe it's platform specific?

Sanchous98 avatar Mar 23 '23 07:03 Sanchous98

I confirmed this issue. Maybe it is a concurrency problem.

orisano avatar Mar 23 '23 08:03 orisano

I confirmed this issue. Maybe it is a concurrency problem.

yeah, it could be, because issues relates to RuntimeContextBuffer which is stored in sync.Pool and fuzz testing launches in my case 16 workers

Sanchous98 avatar Mar 23 '23 14:03 Sanchous98