diff --git a/App/lib/core/Gen/CallGenCtor.vp b/App/lib/core/Gen/CallGenCtor.vp index 4694b19..c35262a 100644 --- a/App/lib/core/Gen/CallGenCtor.vp +++ b/App/lib/core/Gen/CallGenCtor.vp @@ -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(