From 7721beaef015c97c1c7962a44dc2cf99f35e949d Mon Sep 17 00:00:00 2001 From: Scott Leggett Date: Mon, 5 Jan 2026 22:31:03 +0800 Subject: [PATCH 1/2] chore: add failing test case for IsZero() panic If a nil pointer to a type T that implements IsZero() with a value receiver is passed to repr, it will panic due to the nil pointer being automatically dereferenced in the IsZero() method invocation. --- repr_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/repr_test.go b/repr_test.go index a4fd1f8..7ead252 100644 --- a/repr_test.go +++ b/repr_test.go @@ -81,8 +81,9 @@ func TestReprZeroSliceMapFields(t *testing.T) { B bool ZC zeroTest C zeroTest - }{[]string{}, []string{"a", "b"}, map[string]string{}, map[string]string{"a": "b"}, 0, 1, "", "a", false, true, zeroTest{i: 100}, zeroTest{i: 10}} - equal(t, `struct { ZSl []string; Sl []string; ZM map[string]string; M map[string]string; ZI int; I int; ZS string; S string; ZB bool; B bool; ZC repr.zeroTest; C repr.zeroTest }{ZSl: []string{}, Sl: []string{"a", "b"}, ZM: map[string]string{}, M: map[string]string{"a": "b"}, I: 1, S: "a", B: true, C: repr.zeroTest{i: 10}}`, String(v, OmitEmpty(false), OmitZero(true))) + T *time.Time + }{[]string{}, []string{"a", "b"}, map[string]string{}, map[string]string{"a": "b"}, 0, 1, "", "a", false, true, zeroTest{i: 100}, zeroTest{i: 10}, nil} + equal(t, `struct { ZSl []string; Sl []string; ZM map[string]string; M map[string]string; ZI int; I int; ZS string; S string; ZB bool; B bool; ZC repr.zeroTest; C repr.zeroTest; T *time.Time }{ZSl: []string{}, Sl: []string{"a", "b"}, ZM: map[string]string{}, M: map[string]string{"a": "b"}, I: 1, S: "a", B: true, C: repr.zeroTest{i: 10}}`, String(v, OmitEmpty(false), OmitZero(true))) } func TestReprStringArray(t *testing.T) { From 60aa893da7a07ff655b0ffa9c5aa5617d6a93d06 Mon Sep 17 00:00:00 2001 From: Scott Leggett Date: Mon, 5 Jan 2026 23:35:06 +0800 Subject: [PATCH 2/2] fix: avoid panic due to nil dereference in IsZero() call Check if IsZero() is implemented with a value receiver, and avoid calling it if the value is a nil pointer because this will panic. --- repr.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/repr.go b/repr.go index dafa0ac..f3f6d82 100644 --- a/repr.go +++ b/repr.go @@ -299,8 +299,18 @@ func (p *Printer) reprValue(seen map[reflect.Value]bool, v reflect.Value, indent continue } - if p.omitZero && ((ft.Implements(isZeroerType) && f.CanInterface() && f.Interface().(isZeroer).IsZero()) || f.IsZero()) { - continue + if p.omitZero { + // check if this type is a nil pointer to a type implementing IsZero + // with a value receiver and, if so, avoid calling IsZero() on it as + // the method call will automatically dereference the nil pointer and + // panic. + var nilPtrValueReceiver bool + if ft.Kind() == reflect.Pointer && f.IsNil() { + _, nilPtrValueReceiver = ft.Elem().MethodByName("IsZero") + } + if (ft.Implements(isZeroerType) && !nilPtrValueReceiver && f.CanInterface() && f.Interface().(isZeroer).IsZero()) || f.IsZero() { + continue + } } if p.omitEmpty && (f.IsZero() ||