fix(decode): terminate the schema walk on a self-embedded pointer struct

Assisted-by: GLM 5.3
This commit is contained in:
2026-09-17 23:07:53 +02:00
parent bb238c98c3
commit a8d69d90d5
3 changed files with 42 additions and 1 deletions
+10 -1
View File
@@ -255,8 +255,15 @@ type structSchema struct {
func newStructSchema(t reflect.Type) structSchema {
s := structSchema{byName: make(map[string]structFieldLoc, t.NumField())}
// A struct may embed a pointer to itself, which is legal Go, so the walk
// tracks the struct types on the current path and stops when one repeats;
// without the guard the recursion never terminates. A self-promoted key
// always loses to the shallower original, so skipping it changes nothing.
visiting := map[reflect.Type]bool{}
var walk func(t reflect.Type, prefix []int, depth int)
walk = func(t reflect.Type, prefix []int, depth int) {
visiting[t] = true
defer delete(visiting, t)
for i := range t.NumField() {
f := t.Field(i)
if f.PkgPath != "" { // unexported
@@ -277,7 +284,9 @@ func newStructSchema(t reflect.Type) structSchema {
}
switch {
case ft.Kind() == reflect.Struct && !isScalarStruct(ft):
walk(ft, path, depth+1)
if !visiting[ft] {
walk(ft, path, depth+1)
}
continue
case ft.Kind() == reflect.Map && ft.Key().Kind() == reflect.String:
s.embedMaps = append(s.embedMaps, path)