Skip to content

Commit

Permalink
BUGFIX: judge nil pointer stored in error interface
Browse files Browse the repository at this point in the history
  • Loading branch information
FMLS committed Nov 4, 2020
1 parent 404189c commit 1c0c739
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 8 deletions.
3 changes: 1 addition & 2 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@
package zap

import (
"sync"

"go.uber.org/zap/zapcore"
"sync"
)

var _errArrayElemPool = sync.Pool{New: func() interface{} {
Expand Down
23 changes: 20 additions & 3 deletions zapcore/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package zapcore

import (
"fmt"
"reflect"
"sync"
)

Expand All @@ -42,13 +43,29 @@ import (
// ...
// ],
// }
func encodeError(key string, err error, enc ObjectEncoder) error {
func encodeError(key string, err error, enc ObjectEncoder) (retErr error) {
// Try to capture panics (from nil references or otherwise) when calling
// the Error() method
defer func() {
if rerr := recover(); rerr != nil {
// If it's a nil pointer, just say "<nil>". The likeliest causes are a
// Stringer that fails to guard against nil or a nil pointer for a
// value receiver, and in either case, "<nil>" is a nice result.
if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
enc.AddString(key, "<nil>")
return
}

retErr = fmt.Errorf("PANIC=%v", rerr)
}
}()

basic := err.Error()
enc.AddString(key, basic)

switch e := err.(type) {
case errorGroup:
return enc.AddArray(key+"Causes", errArray(e.Errors()))
retErr = enc.AddArray(key+"Causes", errArray(e.Errors()))
case fmt.Formatter:
verbose := fmt.Sprintf("%+v", e)
if verbose != basic {
Expand All @@ -57,7 +74,7 @@ func encodeError(key string, err error, enc ObjectEncoder) error {
enc.AddString(key+"Verbose", verbose)
}
}
return nil
return retErr
}

type errorGroup interface {
Expand Down
6 changes: 3 additions & 3 deletions zapcore/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (f Field) AddTo(enc ObjectEncoder) {
case StringerType:
err = encodeStringer(f.Key, f.Interface, enc)
case ErrorType:
encodeError(f.Key, f.Interface.(error), enc)
err = encodeError(f.Key, f.Interface.(error), enc)
case SkipType:
break
default:
Expand Down Expand Up @@ -209,7 +209,7 @@ func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (retErr
// Try to capture panics (from nil references or otherwise) when calling
// the String() method, similar to https://golang.org/src/fmt/print.go#L540
defer func() {
if err := recover(); err != nil {
if rerr := recover(); rerr != nil {
// If it's a nil pointer, just say "<nil>". The likeliest causes are a
// Stringer that fails to guard against nil or a nil pointer for a
// value receiver, and in either case, "<nil>" is a nice result.
Expand All @@ -218,7 +218,7 @@ func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (retErr
return
}

retErr = fmt.Errorf("PANIC=%v", err)
retErr = fmt.Errorf("PANIC=%v", rerr)
}
}()

Expand Down
9 changes: 9 additions & 0 deletions zapcore/field_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ func (o *obj) String() string {
return "obj"
}

type errObj struct {
errMessage string
}

func (eobj *errObj) Error() string {
return eobj.errMessage
}

func TestUnknownFieldType(t *testing.T) {
unknown := Field{Key: "k", String: "foo"}
assert.Equal(t, UnknownType, unknown.Type, "Expected zero value of FieldType to be UnknownType.")
Expand Down Expand Up @@ -150,6 +158,7 @@ func TestFields(t *testing.T) {
{t: SkipType, want: interface{}(nil)},
{t: StringerType, iface: (*url.URL)(nil), want: "<nil>"},
{t: StringerType, iface: (*users)(nil), want: "<nil>"},
{t: ErrorType, iface: (*errObj)(nil), want: "<nil>"},
}

for _, tt := range tests {
Expand Down

0 comments on commit 1c0c739

Please sign in to comment.