fix: catch a cyclic map by its identity on the document walk
Test / test (push) Successful in 23s

Assisted-by: DeepSeek V4.1 Flash
This commit is contained in:
2026-10-04 22:09:21 +02:00
parent 9a1b922712
commit c2c311a859
+17 -5
View File
@@ -5,6 +5,7 @@ package interpres
import (
"maps"
"reflect"
"slices"
)
@@ -402,13 +403,24 @@ func (t *Table) Set(key string, value any) {
// newOrderedTable builds a table node for a value the caller set, its keys
// entered in sorted order, the order Marshal writes maps in.
func newOrderedTable(m map[string]any) *Table {
return orderedTable(m, 0)
return orderedTable(m, 0, map[uintptr]bool{})
}
// orderedTable is newOrderedTable's recursion. The depth bound is the value
// encoder's: a cyclic map stopped here is written by the value writer, which
// reports it instead of running the stack out.
func orderedTable(m map[string]any, depth int) *Table {
// reports it instead of running the stack out. seen carries the maps the walk
// is inside of, so a map that repeats one of them is caught by its identity
// at once and takes the depth limit's shape: its entries are recorded and the
// walk stops, instead of the walk and the emission materialising a chain the
// input does not hold.
func orderedTable(m map[string]any, depth int, seen map[uintptr]bool) *Table {
id := reflect.ValueOf(m).Pointer()
if seen[id] {
depth = maxEncodeDepth
} else {
seen[id] = true
defer delete(seen, id)
}
t := newTable(m)
for _, k := range slices.Sorted(maps.Keys(m)) {
v := m[k]
@@ -418,11 +430,11 @@ func orderedTable(m map[string]any, depth int) *Table {
}
switch val := v.(type) {
case map[string]any:
e.child = orderedTable(val, depth+1)
e.child = orderedTable(val, depth+1, seen)
case []map[string]any:
e.elements = make([]*Table, len(val))
for i, item := range val {
e.elements[i] = orderedTable(item, depth+1)
e.elements[i] = orderedTable(item, depth+1, seen)
}
}
}