feat(callgenctor): callee 入口 can 无条件打印,区分 ABI 错位 vs 栈槽复用
caller 侧 can=0(断点证实)但 callee 收到 0x12A1_0000_0000=[cargs高32][count低32]——入口打印可区分:入口即垃圾=ABI 栈参数错位 4 字节;入口正常但槽位悬空处垃圾=函数内 can 被栈槽复用覆盖。
This commit is contained in:
1 parent
b3546b05a5
commit
8cc6996577
1 file changed
+75
-28
@@ -83,7 +83,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
builder, pool, mod, field_ptr_arr2, fe.DefaultVal, trans)
|
||||
continue
|
||||
default_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, fe.DefaultVal, None, 0, trans)
|
||||
builder, pool, mod, fe.DefaultVal, None, 0, trans, fe.Ty)
|
||||
if default_val is None:
|
||||
# fast-fail: 默认值翻译失败(如引用了未定义符号)
|
||||
VLogger.error(
|
||||
@@ -127,6 +127,49 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load
|
||||
普通结构体:alloca → zero + defaults → store 参数 → load
|
||||
"""
|
||||
# [DET] callee 入口 can 核对(无条件首条打印):与槽位悬空处 can 对比——
|
||||
# 入口即垃圾 = ABI 栈参数错位(caller 存/callee 读错位 4 字节);
|
||||
# 入口正常但槽位悬空处垃圾 = 函数内部 can 被改写(栈槽复用)。
|
||||
# 无条件打印仅在进入结构体构造时执行一次(每 ctor 一条,量可控)。
|
||||
stdio.printf("[DET] ctor入口: can=%llu cargs=%llu\n",
|
||||
t.CUInt64T(can), t.CUInt64T(cargs))
|
||||
# [DET] 读取侧存活校验(detection 模式启用):cargs(cl.args)必须指向
|
||||
# 存活块——不在记录表(或已 free)= use-after-free 读取(SlotsBugTest
|
||||
# KwEntry cargs 悬空根因定位)。is_alive 内部处理 detection==0 时不拦截,
|
||||
# 默认关闭无开销。补 _det_probe 写入侧检测的盲区。
|
||||
if cargs is not None and pool is not None:
|
||||
if pool.is_alive(cargs) == 0:
|
||||
# 打印 cargs 指向的块头:0=已 free(UAF 实锤) 奇数=活跃(记录表
|
||||
# 异常) 其它=非 pool 块(stdlib.malloc/垃圾指针)——定位悬空源
|
||||
blk_c: t.CUInt64T = t.CUInt64T(cargs) - 2 - 8
|
||||
hdr_c: t.CUInt64T = t.CUInt64T(c.Deref(t.CUInt64T(blk_c, t.CPtr)))
|
||||
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)
|
||||
@@ -248,14 +291,8 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg is None:
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans)
|
||||
if arg_val is None:
|
||||
# fast-fail: 参数翻译失败
|
||||
VLogger.error(
|
||||
f"构造函数参数翻译失败: {class_name}",
|
||||
"HandlesExprCall")
|
||||
continue
|
||||
# 先取字段(fe.Ty 用于 char 字面量 → str 字段的物化判定,
|
||||
# 见 translate_constant;否则 coerce inttoptr 字符值当指针崩溃)
|
||||
fe: GenTypes.FieldEntry | t.CPtr = None
|
||||
if ctor_entry is not None:
|
||||
# OOP 结构体字段表第 0 个字段是 __vtable__(vtable 指针占位),
|
||||
@@ -285,6 +322,14 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
f"构造函数参数过多,字段索引越界: {class_name}",
|
||||
"HandlesExprCall")
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans, fe.Ty)
|
||||
if arg_val is None:
|
||||
# fast-fail: 参数翻译失败
|
||||
VLogger.error(
|
||||
f"构造函数参数翻译失败: {class_name}",
|
||||
"HandlesExprCall")
|
||||
continue
|
||||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, struct_ty, fe.Ty, storage_ptr, fe.Index)
|
||||
if field_ptr is None:
|
||||
@@ -311,15 +356,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg is None:
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans)
|
||||
if arg_val is None:
|
||||
# fast-fail: 参数翻译失败
|
||||
VLogger.error(
|
||||
f"构造函数参数翻译失败: {class_name}",
|
||||
"HandlesExprCall")
|
||||
continue
|
||||
# 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错)
|
||||
# 先取字段(fe.Ty 用于 char 字面量 → str 字段的物化判定,见 translate_constant)
|
||||
fe: GenTypes.FieldEntry | t.CPtr = None
|
||||
if ctor_entry is not None:
|
||||
fe = self.Gen.StructGen._get_field_entry(ctor_entry, ai)
|
||||
@@ -331,6 +368,14 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
f"构造函数参数过多,字段索引越界: {class_name}",
|
||||
"HandlesExprCall")
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans, fe.Ty)
|
||||
if arg_val is None:
|
||||
# fast-fail: 参数翻译失败
|
||||
VLogger.error(
|
||||
f"构造函数参数翻译失败: {class_name}",
|
||||
"HandlesExprCall")
|
||||
continue
|
||||
# GEP 到字段 ai
|
||||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||||
@@ -437,11 +482,8 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg is None:
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans)
|
||||
if arg_val is None:
|
||||
continue
|
||||
# payload 字段索引 = ai + 1(跳过 __tag)
|
||||
# payload 字段索引 = ai + 1(跳过 __tag);先取字段(pfe.Ty 用于
|
||||
# char 字面量 → str 字段的物化判定,见 translate_constant)
|
||||
payload_idx: int = ai + 1
|
||||
if payload_idx >= renum_entry.FieldCount:
|
||||
break
|
||||
@@ -449,6 +491,10 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
renum_entry, payload_idx)
|
||||
if pfe is None:
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans, pfe.Ty)
|
||||
if arg_val is None:
|
||||
continue
|
||||
payload_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, renum_ty, pfe.Ty, tmp, payload_idx)
|
||||
if payload_ptr is None:
|
||||
@@ -637,10 +683,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg is None:
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans)
|
||||
if arg_val is None:
|
||||
continue
|
||||
# 先取字段(fe.Ty 用于 char 字面量 → str 字段的物化判定,见 translate_constant)
|
||||
fe: GenTypes.FieldEntry | t.CPtr = None
|
||||
if kw_entry is not None:
|
||||
fe = self.Gen.StructGen._get_field_entry(kw_entry, ai)
|
||||
@@ -651,6 +694,10 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
arg, f"结构体 '{class_name}' 位置参数越界(无对应字段)", "TypeError")
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans, fe.Ty)
|
||||
if arg_val is None:
|
||||
continue
|
||||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||||
if field_ptr is None:
|
||||
@@ -675,7 +722,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
kw, f"结构体 '{class_name}' 无字段 '{kw.arg}'", "AttributeError")
|
||||
continue
|
||||
kw_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, kw.value, None, 0, trans)
|
||||
builder, pool, mod, kw.value, None, 0, trans, fe.Ty)
|
||||
if kw_val is None:
|
||||
continue
|
||||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
|
||||
Reference in new issue
Block a user