## 位置 oekit/pkg @ origin/main - `reflectx/copy.go:93-101` —— `case reflect.Pointer`:`visited[v.Pointer()]` 登记 + 自引用环终止 - `reflectx/copy.go:54` —— `case reflect.Map`:无 visited 登记 - `reflectx/copy.go:64` —— `case reflect.Slice`:无 visited 登记 ## 为什么错 环检测**只挂在 Pointer 分支**。但不经 Pointer 也能成环: ```go m := map[string]any{} m["self"] = m // map 自引用——Map 分支直接递归,visited 无登记 s := []any{nil} s[0] = s // slice 头自引用——同理 ``` Pointer 分支的 `visited[v.Pointer()]` 只保护 `*T` 指针解引用环(copy.go:97-101 注释「自引用环在此终止」)——**Map/Slice 分支对同族环零防护**,递归深度无上限直至 `goroutine stack exceeds` fatal(进程崩溃,非 error)。 ## 影响 拷贝含自引用/互引用 map、slice 的结构(缓存快照、父指针邻接表、序列化中间态)→ **整进程 stack overflow 崩溃**;「深拷贝可返回 error」的调用方契约被 fatal 短路。#420 是 errors 链成环的同族问题(另一域,已单独立项),reflectx 这面是拷贝器本体。 ## 修法 Map/Slice 分支同样防护。reflect 限制:`v.Pointer()` 可用于 Slice(首元素地址),**Map 不可用**——务实方案: 1. Slice:`v.Pointer()` 进 visited(与 Pointer 分支同键语义); 2. Map:`v.Pointer()` 不支持 → **深度上限**(如 64 层)+ 显式错误返回,或以 `reflect.ValueOf` 之外的稳定键(如遍历父链比对 `v.Len()+类型` 启发式不可靠——直接深度上限最稳); 3. 无论方案,环/超深必须**返回 error 而非 fatal**,对齐本包「拷贝可失败」的既有错误面; 4. 回归测试:map 自引用、slice 自引用、双向互引 map 三例断言返回 error(非 crash)。 ## 去重 - #420(open):errors KvFromChain 成环——链遍历域,非 reflectx 拷贝器; - pkg open 无 reflectx 单;#391 是 StructToMap json tag 面,不同。
Activity
Merge pull request #429 from oekit/sweep/20261112-l1-b3
zy84338719 commentedon Nov 12, 2026
已合入修复 ✅(无 SemVer 发布:本次改动不发版本)
变更内容
reflectx DeepCopy Map/Slice 分支与 Pointer 同口径先注册再下探 visited,自引用不再 stack overflow
合入:PR #429(https://github.com/oekit/pkg/pull/429),merge commit
6ee91ff5,2026-11-12T18:18:08ZCI:
link✅ /Lint & Test / Test✅ /Lint & Test / Lint✅ /Zero Third-Party Deps✅