Skip to content

Commit 91f8d24

Browse files
committed
fix: field index out of bounds
1 parent 42f71c0 commit 91f8d24

File tree

2 files changed

+89
-4
lines changed

2 files changed

+89
-4
lines changed

godump.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,11 @@ func printValue(tw *tabwriter.Writer, v reflect.Value, indent int, visited map[u
216216
t := v.Type()
217217
fmt.Fprintf(tw, "%s ", colorize(colorGray, "#"+t.String()))
218218
fmt.Fprintln(tw)
219-
for i, _ := range reflect.VisibleFields(t) {
220-
field := t.Field(i)
221-
fieldVal := v.Field(i)
219+
visibleFields := reflect.VisibleFields(t)
220+
for _, field := range visibleFields {
221+
fieldVal := v.FieldByIndex(field.Index)
222222
symbol := "+"
223-
if field.PkgPath != "" { // private
223+
if field.PkgPath != "" {
224224
symbol = "-"
225225
fieldVal = forceExported(fieldVal)
226226
}

godump_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,3 +487,88 @@ func timePtrsEqual(a, b *time.Time) bool {
487487
}
488488
return a.Equal(*b)
489489
}
490+
491+
func TestPanicOnVisibleFieldsIndexMismatch(t *testing.T) {
492+
type Embedded struct {
493+
Secret string
494+
}
495+
type Outer struct {
496+
Embedded // Promoted field
497+
Age int
498+
}
499+
500+
// This will panic with:
501+
// panic: reflect: Field index out of bounds
502+
_ = DumpStr(Outer{
503+
Embedded: Embedded{Secret: "classified"},
504+
Age: 42,
505+
})
506+
}
507+
508+
type FriendlyDuration time.Duration
509+
510+
func (fd FriendlyDuration) String() string {
511+
td := time.Duration(fd)
512+
return fmt.Sprintf("%02d:%02d:%02d", int(td.Hours()), int(td.Minutes())%60, int(td.Seconds())%60)
513+
}
514+
515+
func TestTheKitchenSink(t *testing.T) {
516+
517+
type Inner struct {
518+
ID int
519+
Notes []string
520+
}
521+
522+
type Ref struct {
523+
Self *Ref
524+
}
525+
526+
type Everything struct {
527+
String string
528+
Bool bool
529+
Int int
530+
Float float64
531+
Time time.Time
532+
Duration time.Duration
533+
Friendly FriendlyDuration
534+
PtrString *string
535+
PtrDuration *time.Duration
536+
SliceInts []int
537+
ArrayStrings [2]string
538+
MapValues map[string]int
539+
Nested Inner
540+
NestedPtr *Inner
541+
Interface any
542+
Recursive *Ref
543+
privateField string
544+
privateStruct Inner
545+
}
546+
547+
now := time.Now()
548+
ptrStr := "Hello"
549+
dur := time.Minute * 20
550+
551+
val := Everything{
552+
String: "test",
553+
Bool: true,
554+
Int: 42,
555+
Float: 3.1415,
556+
Time: now,
557+
Duration: dur,
558+
Friendly: FriendlyDuration(dur),
559+
PtrString: &ptrStr,
560+
PtrDuration: &dur,
561+
SliceInts: []int{1, 2, 3},
562+
ArrayStrings: [2]string{"foo", "bar"},
563+
MapValues: map[string]int{"a": 1, "b": 2},
564+
Nested: Inner{ID: 10, Notes: []string{"alpha", "beta"}},
565+
NestedPtr: &Inner{ID: 99, Notes: []string{"x", "y"}},
566+
Interface: map[string]bool{"ok": true},
567+
Recursive: &Ref{},
568+
privateField: "should show",
569+
privateStruct: Inner{ID: 5, Notes: []string{"private"}},
570+
}
571+
val.Recursive.Self = val.Recursive // cycle
572+
573+
Dump(val)
574+
}

0 commit comments

Comments
 (0)