From c1abff8c3d9ba6e4d44ae0cb657dfec5ff6c5112 Mon Sep 17 00:00:00 2001 From: Dan Laine Date: Thu, 26 Mar 2020 15:14:45 -0400 Subject: [PATCH] fix bug where unmarshalling into improper type causes panic. Add test for this --- vms/components/codec/codec.go | 5 ++++ vms/components/codec/codec_test.go | 39 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/vms/components/codec/codec.go b/vms/components/codec/codec.go index a80d9bc..efbc5a0 100644 --- a/vms/components/codec/codec.go +++ b/vms/components/codec/codec.go @@ -324,6 +324,11 @@ func (c codec) unmarshal(p *wrappers.Packer, field reflect.Value) error { if !ok { return errUnmarshalUnregisteredType } + // Ensure struct actually does implement the interface + fieldType := field.Type() + if !typ.Implements(fieldType) { + return fmt.Errorf("%s does not implement interface %s", typ, fieldType) + } concreteInstancePtr := reflect.New(typ) // instance of the proper type // Unmarshal into the struct if err := c.unmarshal(p, concreteInstancePtr.Elem()); err != nil { diff --git a/vms/components/codec/codec_test.go b/vms/components/codec/codec_test.go index 6fc4f25..336837f 100644 --- a/vms/components/codec/codec_test.go +++ b/vms/components/codec/codec_test.go @@ -538,3 +538,42 @@ func TestTooLargeUnmarshal(t *testing.T) { t.Fatalf("Should have errored due to too many bytes provided") } } + +type outerInterface interface { + ToInt() int +} + +type outer struct { + Interface outerInterface `serialize:"true"` +} + +type innerInterface struct{} + +func (it *innerInterface) ToInt() int { + return 0 +} + +type innerNoInterface struct{} + +// Ensure deserializing structs into the wrong interface errors gracefully +func TestUnmarshalInvalidInterface(t *testing.T) { + codec := NewDefault() + + codec.RegisterType(&innerInterface{}) + codec.RegisterType(&innerNoInterface{}) + + { + bytes := []byte{0, 0, 0, 0} + s := outer{} + if err := codec.Unmarshal(bytes, &s); err != nil { + t.Fatal(err) + } + } + { + bytes := []byte{0, 0, 0, 1} + s := outer{} + if err := codec.Unmarshal(bytes, &s); err == nil { + t.Fatalf("should have errored") + } + } +}