diff options
author | KimMachineGun <geon0250@gmail.com> | 2020-09-29 10:03:38 +0000 |
---|---|---|
committer | Filippo Valsorda <filippo@golang.org> | 2020-09-29 10:31:59 +0000 |
commit | a28edbfca276307b228eb4b154bc2d137a3cba4a (patch) | |
tree | 7a364b1e10eef488549543a4c7bee6771b4351f3 /src/encoding | |
parent | 79e681d2a291142aa0ac8297229e182b2d1a78ac (diff) | |
download | go-a28edbfca276307b228eb4b154bc2d137a3cba4a.tar.gz go-a28edbfca276307b228eb4b154bc2d137a3cba4a.zip |
encoding/asn1: error instead of panic on invalid value to Unmarshal
Changes Unmarshal to return an error, instead of
panicking when its value is nil or not a pointer.
This change matches the behavior of other encoding
packages like json.
Fixes #41509.
Change-Id: I92c3af3a960144566e4c2b55d00c3a6fe477c8d5
GitHub-Last-Rev: c668b6e4ad826f84542c2675eb31ccfb010c45bb
GitHub-Pull-Request: golang/go#41485
Reviewed-on: https://go-review.googlesource.com/c/go/+/255881
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
Trust: Emmanuel Odeke <emm.odeke@gmail.com>
Diffstat (limited to 'src/encoding')
-rw-r--r-- | src/encoding/asn1/asn1.go | 27 | ||||
-rw-r--r-- | src/encoding/asn1/asn1_test.go | 23 |
2 files changed, 47 insertions, 3 deletions
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go index d809dde278..fa3d4e327b 100644 --- a/src/encoding/asn1/asn1.go +++ b/src/encoding/asn1/asn1.go @@ -1035,7 +1035,8 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { // Unmarshal parses the DER-encoded ASN.1 data structure b // and uses the reflect package to fill in an arbitrary value pointed at by val. // Because Unmarshal uses the reflect package, the structs -// being written to must use upper case field names. +// being written to must use upper case field names. If val +// is nil or not a pointer, Unmarshal returns an error. // // After parsing b, any bytes that were leftover and not used to fill // val will be returned in rest. When parsing a SEQUENCE into a struct, @@ -1095,11 +1096,31 @@ func Unmarshal(b []byte, val interface{}) (rest []byte, err error) { return UnmarshalWithParams(b, val, "") } +// An invalidUnmarshalError describes an invalid argument passed to Unmarshal. +// (The argument to Unmarshal must be a non-nil pointer.) +type invalidUnmarshalError struct { + Type reflect.Type +} + +func (e *invalidUnmarshalError) Error() string { + if e.Type == nil { + return "asn1: Unmarshal recipient value is nil" + } + + if e.Type.Kind() != reflect.Ptr { + return "asn1: Unmarshal recipient value is non-pointer " + e.Type.String() + } + return "asn1: Unmarshal recipient value is nil " + e.Type.String() +} + // UnmarshalWithParams allows field parameters to be specified for the // top-level element. The form of the params is the same as the field tags. func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err error) { - v := reflect.ValueOf(val).Elem() - offset, err := parseField(v, b, 0, parseFieldParameters(params)) + v := reflect.ValueOf(val) + if v.Kind() != reflect.Ptr || v.IsNil() { + return nil, &invalidUnmarshalError{reflect.TypeOf(val)} + } + offset, err := parseField(v.Elem(), b, 0, parseFieldParameters(params)) if err != nil { return nil, err } diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go index 8daae97faa..8985538468 100644 --- a/src/encoding/asn1/asn1_test.go +++ b/src/encoding/asn1/asn1_test.go @@ -518,6 +518,29 @@ func TestUnmarshal(t *testing.T) { } } +func TestUnmarshalWithNilOrNonPointer(t *testing.T) { + tests := []struct { + b []byte + v interface{} + want string + }{ + {b: []byte{0x05, 0x00}, v: nil, want: "asn1: Unmarshal recipient value is nil"}, + {b: []byte{0x05, 0x00}, v: RawValue{}, want: "asn1: Unmarshal recipient value is non-pointer asn1.RawValue"}, + {b: []byte{0x05, 0x00}, v: (*RawValue)(nil), want: "asn1: Unmarshal recipient value is nil *asn1.RawValue"}, + } + + for _, test := range tests { + _, err := Unmarshal(test.b, test.v) + if err == nil { + t.Errorf("Unmarshal expecting error, got nil") + continue + } + if g, w := err.Error(), test.want; g != w { + t.Errorf("InvalidUnmarshalError mismatch\nGot: %q\nWant: %q", g, w) + } + } +} + type Certificate struct { TBSCertificate TBSCertificate SignatureAlgorithm AlgorithmIdentifier |