protocol/validation: nil pointer during ValidateTx
jbowens opened this issue · comments
Fuzz testing found a transaction for which ValidateTx will panic with a nil pointer deference:
Here's an individual test case that can be put into the protocol/validation package to repro: https://gist.github.com/jbowens/5f0fb08beac2eb2a4c33937302c62127
Here's the stack trace:
=== RUN TestFuzzNilPointer
--- FAIL: TestFuzzNilPointer (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x11830e8]
goroutine 5 [running]:
testing.tRunner.func1(0xc42006e8f0)
/usr/local/go/src/testing/testing.go:622 +0x29d
panic(0x11c3740, 0x12e01d0)
/usr/local/go/src/runtime/panic.go:489 +0x2cf
chain/protocol/validation.checkValidDest(0xc4200f3b78, 0xc42000b040, 0x0, 0xc42000ade0)
/Users/jackson/src/chain/protocol/validation/validation.go:394 +0x5b8
chain/protocol/validation.checkValid(0xc4200f4070, 0x12c8980, 0xc4200ec030, 0xc4200c8e08, 0x1)
/Users/jackson/src/chain/protocol/validation/validation.go:106 +0x1f5c
chain/protocol/validation.checkValidSrc(0xc4200f4e18, 0xc42000aea0, 0x10000c4200c8b60, 0xc4200ba128)
/Users/jackson/src/chain/protocol/validation/validation.go:313 +0x119
chain/protocol/validation.checkValid(0xc420018d80, 0x12c8a40, 0xc4200ec090, 0xc4200c8e18, 0x20)
/Users/jackson/src/chain/protocol/validation/validation.go:171 +0x1ba0
chain/protocol/validation.checkValid(0xc4200f5e70, 0x12c8bc0, 0xc42000c0e0, 0x0, 0x8000101)
/Users/jackson/src/chain/protocol/validation/validation.go:72 +0x41ca
chain/protocol/validation.ValidateTx(0xc4200a6090, 0x50935a092ffad7ec, 0x9fbac4f4486db6c3, 0xb8cd5b9f51cf6972, 0x48584dde286a7220, 0x0, 0xc4200c8b60)
/Users/jackson/src/chain/protocol/validation/validation.go:478 +0xde
chain/protocol/validation.TestFuzzNilPointer(0xc42006e8f0)
/Users/jackson/src/chain/protocol/validation/fuzz_test.go:28 +0x22f
testing.tRunner(0xc42006e8f0, 0x12048d0)
/usr/local/go/src/testing/testing.go:657 +0x96
created by testing.(*T).Run
/usr/local/go/src/testing/testing.go:697 +0x2ca
exit status 2
FAIL chain/protocol/validation 0.011s
Should we be using the proto-generated getters to avoid nil panics? Or performing nil checks along the way? It looks like most of the validation code assumes the bc.Tx
type is well-formed and omits nil checks.
Any thoughts on collapsing the Body and Witness bc protos into their parent messages? Removing indirection would help get rid of a lot of nil checks.
Instead of an entry.body method we could have a entry.writeBody() method that calls writeForHash for the relevant fields.
I wonder if we should just use protobufs for transport and then define validation in terms of plain Go types. We already talked about maybe changing our protobuf representation of the txgraph so that we reduce some of the bloat. We could optimize the protobufs for a small wire footprint and implement a mapping to Go types that are optimized for convenience.