feat(callgenctor): 构造参数列表头+槽位 0xCDCD 诊断

ASAN 崩溃 node=0xCDCDCDCDCDCDCDCD(_translate_struct_ctor → translate_value)确认:is_alive(cargs) 只验列表结构体,get() 读的是 __data__ 数组——两者都可能未初始化(MEMBUDDY_FILL_GUARD 无条件填 0xCD)或悬空。

新增:读取列表头(__data__@0 __count__@8 __capacity__@16),命中 0xCDCD 打印定位 fail-fast;预检每个实参槽位 0xCDCD 并打印 ai/can/data/count/cap。区分列表未初始化 vs 槽位悬空两种根因分支。
This commit is contained in:
TermiNexus committed 2026-08-25 16:29:48 +08:00
1 parent 7c7629852a
commit 3ac48282a3
1 file changed
+24
+24
View File
@@ -140,6 +140,30 @@ class CallGenCtor(CallGenBase.CallGenBase):
stdio.printf("[DET] 读取悬空: struct-ctor cargs=%llu block=%llu hdr=0x%llX(0=free 奇数=活跃 其它=非pool块)\n",
t.CUInt64T(cargs), blk_c, hdr_c)
stdlib.exit(1)
# [DET] 扩展:cargs 列表存活但槽位/数据可能未初始化或悬空(SlotsBugTest
# ASAN 崩溃 node=0xCDCDCDCDCDCDCDCD——cargs.get(ai) 返回 0xCDCD 填充值:
# 列表 __init__ 未执行(__data__/__count__=0xCDCD,MEMBUDDY_FILL_GUARD
# 无条件填充)或 __data__ 悬空。列表头:__data__@0 __count__@8
# __capacity__@16。命中 0xCDCD 即打印定位并 fail-fast。
if cargs is not None:
cd_fill: t.CUInt64T = (t.CUInt64T(0xCDCDCDCD) << 32) | t.CUInt64T(0xCDCDCDCD)
lh_c: t.CUInt64T | t.CPtr = (t.CUInt64T | t.CPtr)(t.CVoid(cargs, t.CPtr))
ldd_c: t.CUInt64T = lh_c[0]
ldc_c: t.CUInt64T = lh_c[1]
ldcap_c: t.CUInt64T = lh_c[2]
if ldd_c == cd_fill or ldc_c == cd_fill:
stdio.printf("[DET] 构造参数列表未初始化: cargs=%llu data=%llu count=%llu cap=%llu can=%llu\n",
t.CUInt64T(cargs), ldd_c, ldc_c, ldcap_c, t.CUInt64T(can))
stdlib.exit(1)
ai_c: t.CSizeT = 0
while ai_c < can:
nd_c: ast.AST | t.CPtr = cargs.get(ai_c)
if nd_c is not None and t.CUInt64T(nd_c) == cd_fill:
stdio.printf("[DET] 构造参数槽位悬空: ai=%zu can=%llu node=%llu cargs=%llu data=%llu count=%llu cap=%llu\n",
ai_c, t.CUInt64T(can), t.CUInt64T(nd_c), t.CUInt64T(cargs),
ldd_c, ldc_c, ldcap_c)
stdlib.exit(1)
ai_c += 1
# 创建临时 alloca
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty)