From fefc1e8343340b58d0c047d4309f9bfe486d5ef4 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 25 Aug 2026 15:31:39 +0800 Subject: [PATCH] =?UTF-8?q?feat(memhub):=20=E8=AF=BB=E5=8F=96=E4=BE=A7?= =?UTF-8?q?=E5=AD=98=E6=B4=BB=E6=A0=A1=E9=AA=8C=20is=5Falive=20-=20?= =?UTF-8?q?=E8=A1=A5=20detection=20=E5=86=99=E5=85=A5=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=E7=9B=B2=E5=8C=BA=EF=BC=9Astruct=5Fctor=20=E8=AF=BB=20cargs=20?= =?UTF-8?q?=E5=89=8D=E6=A0=A1=E9=AA=8C=20cl.args=20=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=9C=A8=E8=AE=B0=E5=BD=95=E8=A1=A8=20active=20=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E4=B8=AD=EF=BC=8C=E4=B8=8D=E5=9C=A8=E5=8D=B3=20[DET]?= =?UTF-8?q?=20=E8=AF=BB=E5=8F=96=E6=82=AC=E7=A9=BA=20=E6=89=93=E5=8D=B0=20?= =?UTF-8?q?cargs=20=E5=80=BC=E5=B9=B6=E7=BB=88=E6=AD=A2=EF=BC=9B=E6=8B=A6?= =?UTF-8?q?=E6=88=AA=20use-after-free=20=E8=AF=BB=E5=8F=96=EF=BC=88SlotsBu?= =?UTF-8?q?gTest=20KwEntry=20cargs=3Dcl.args=20=E6=82=AC=E7=A9=BA=E6=A0=B9?= =?UTF-8?q?=E5=9B=A0=EF=BC=89=EF=BC=8Cdetection=3D=3D0=20=E6=97=B6=20is=5F?= =?UTF-8?q?alive=20=E6=81=92=E8=BF=94=E5=9B=9E=201=20=E4=B8=8D=E6=8B=A6?= =?UTF-8?q?=E6=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TransPyV/App/lib/core/Gen/CallGenCtor.vp | 9 +++++++++ includes/memhub.vp | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/TransPyV/App/lib/core/Gen/CallGenCtor.vp b/TransPyV/App/lib/core/Gen/CallGenCtor.vp index ab23ef4..14a4cc2 100644 --- a/TransPyV/App/lib/core/Gen/CallGenCtor.vp +++ b/TransPyV/App/lib/core/Gen/CallGenCtor.vp @@ -127,6 +127,15 @@ class CallGenCtor(CallGenBase.CallGenBase): OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load 普通结构体:alloca → zero + defaults → store 参数 → load """ + # [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: + stdio.printf("[DET] 读取悬空: struct-ctor cargs=%llu 不在存活记录(cl.args 悬空 = use-after-free 读取)\n", + t.CUInt64T(cargs)) + stdlib.exit(1) # 创建临时 alloca # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) diff --git a/includes/memhub.vp b/includes/memhub.vp index a7dca70..7b4dc56 100644 --- a/includes/memhub.vp +++ b/includes/memhub.vp @@ -786,6 +786,29 @@ class MemBuddy(MemManager): self.free(ptr) return new_ptr + # ============================================================ + # [DET] is_alive - 读取侧存活校验:ptr 是否在当前记录表的 active + # 记录中(alloc 后未 free)。返回 1=存活 / 0=悬空(不在记录或已 + # free)。detection 关闭或记录表不可用时返回 1(不拦截)。 + # 补 _det_probe 盲区:写入侧检测(标记/0xCD)拦不住 use-after-free + # 读取(如 SlotsBugTest KwEntry cargs=cl.args 悬空指向复用块)。 + # ============================================================ + def is_alive(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + if self.detection == 0: + return 1 + if self._det_records is None: + return 1 + target: t.CUInt64T = t.CUInt64T(ptr) + free_flag: t.CUInt64T = t.CUInt64T(1) << 63 + i: t.CSizeT = 0 + while i < self._det_count: + rp: t.CUInt64T = self._det_records[i * 2] + rs: t.CUInt64T = self._det_records[i * 2 + 1] + if rp == target and (rs & free_flag) == 0: + return 1 + i += 1 + return 0 + # ============================================================ # [DET] _det_probe - 分配检测探测:遍历记录表,验证每个存活块的 # 后标记(返回 ptr + size 处 2 字节)仍为 0xCDCD。