xerrors: check for nil pointers in As's target
As already checks for a nil or non-pointer target; check for nil pointers
as well. Produces a better error message and catches incorrect target
parameters even when the target doesn't match the error.
Change-Id: I06efb4b78f640b17076f002519d275b328b42557
Reviewed-on: https://go-review.googlesource.com/c/161657
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/wrap.go b/wrap.go
index 2462d3d..3e71058 100644
--- a/wrap.go
+++ b/wrap.go
@@ -79,14 +79,15 @@
if target == nil {
panic("errors: target cannot be nil")
}
- typ := reflect.TypeOf(target)
- if typ.Kind() != reflect.Ptr {
- panic("errors: target must be a pointer")
+ val := reflect.ValueOf(target)
+ typ := val.Type()
+ if typ.Kind() != reflect.Ptr || val.IsNil() {
+ panic("errors: target must be a non-nil pointer")
}
targetType := typ.Elem()
for {
if reflect.TypeOf(err).AssignableTo(targetType) {
- reflect.ValueOf(target).Elem().Set(reflect.ValueOf(err))
+ val.Elem().Set(reflect.ValueOf(err))
return true
}
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
diff --git a/wrap_test.go b/wrap_test.go
index 2380190..ef6a9ed 100644
--- a/wrap_test.go
+++ b/wrap_test.go
@@ -150,6 +150,27 @@
}
}
+func TestAsValidation(t *testing.T) {
+ testCases := []interface{}{
+ nil,
+ (*int)(nil),
+ "error",
+ }
+ err := xerrors.New("error")
+ for _, tc := range testCases {
+ t.Run(fmt.Sprintf("%T(%v)", tc, tc), func(t *testing.T) {
+ defer func() {
+ recover()
+ }()
+ if xerrors.As(err, tc) {
+ t.Errorf("As(err, %T(%v)) = true, want false", tc, tc)
+ return
+ }
+ t.Errorf("As(err, %T(%v)) did not panic", tc, tc)
+ })
+ }
+}
+
func TestUnwrap(t *testing.T) {
err1 := xerrors.New("1")
erra := xerrors.Errorf("wrap 2: %w", err1)