From 3100bb9343820ec6928339cce05d47946e36bd11 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 25 Aug 2026 13:19:08 +0800 Subject: [PATCH] =?UTF-8?q?feat(memhub,list,llvmlite):=200xCD=20=E5=88=86?= =?UTF-8?q?=E9=85=8D=E5=AE=88=E5=8D=AB=E3=80=81=E8=AF=8A=E6=96=AD=E5=BC=80?= =?UTF-8?q?=E5=85=B3=E4=B8=8E=20INT64=5FMIN=20=E5=B8=B8=E9=87=8F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20-=20memhub.vp=20alloc=20=E5=A1=AB=E5=85=85=200xCD?= =?UTF-8?q?=20=E5=93=A8=E5=85=B5=20+=20set=5Fdebug=5Flog/get=5Fdebug=5Flog?= =?UTF-8?q?=20+=20ALLOCDBG=20=E5=88=86=E9=85=8D=E8=80=85=E8=AE=B0=E5=BD=95?= =?UTF-8?q?;=20=5Flist.vp=20=5F=5Finit=5F=5F/append=20=E8=AF=8A=E6=96=AD;?= =?UTF-8?q?=20llvmlite=20i64=20INT64=5FMIN=20=E8=BE=93=E5=87=BA=E6=97=A0?= =?UTF-8?q?=E7=AC=A6=E5=8F=B7=E4=BD=8D=E6=A8=A1=E5=BC=8F(LLVM=20=E6=8B=92?= =?UTF-8?q?=E7=BB=9D=20-9223372036854775808=20=E5=AD=97=E9=9D=A2=E9=87=8F)?= =?UTF-8?q?=E3=80=82=E5=AE=9A=E4=BD=8D=20SlotsBugTest=20KwEntry=20cargs=20?= =?UTF-8?q?use-after-free=20=E4=B8=8E=E5=B8=B8=E9=87=8F=20dump=20=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/_list.vp | 21 +++++++++++++++ includes/llvmlite/__init__.vp | 9 ++++++- includes/memhub.vp | 50 +++++++++++++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/includes/_list.vp b/includes/_list.vp index 5e60cf6..824ba17 100644 --- a/includes/_list.vp +++ b/includes/_list.vp @@ -1,8 +1,13 @@ import t, c import memhub import string +import stdio from stdint import * +# [LISTDBG] 诊断(用后移除):list.__init__ 打印初始化结果、append 首次 +# (Count==0) 打印 self/Data,配合 CTORDBG 定位二代编 SlotsBugTest cargs(list) +# 头覆盖。默认静默——由命令行 --enable-debug-log 开启(memhub.set_debug_log) + class list[T]: """Heap-allocated dynamic list container backed by memhub.MemManager polymorphic allocator. @@ -37,11 +42,27 @@ class list[T]: self.__elem_size__ = elem_size self.__data__ = pool.alloc(self.__capacity__ * self.__elem_size__) self.__iter_index__ = 0 + # [LISTDBG] 诊断(用后移除):打印初始化结果,与 CTORDBG cargs 六字段 + # 交叉匹配:找到 cargs 对应记录即可判断 __init__ 是否执行/写入是否正确 + if memhub.get_debug_log() != 0: + stdio.printf("[LISTDBG] list-init self=%llu data=%llu cnt=%llu cap=%llu pool=%llu es=%llu iter=%llu\n", + t.CUInt64T(self), t.CUInt64T(self.__data__), + t.CUInt64T(self.__count__), t.CUInt64T(self.__capacity__), + t.CUInt64T(self.__pool__), t.CUInt64T(self.__elem_size__), + t.CUInt64T(self.__iter_index__)) def __len__(self) -> t.CSizeT: return self.__count__ def append(self, item: T): + # [LISTDBG] 诊断(用后移除):仅首次 append(Count==0)打印,确认 + # append 作用在哪个 list、Data 指针是否有效(若 cargs 覆盖发生在此 + # 前后,日志能显示 append 的 self/data 与 CTORDBG cargs/d0 的对应) + if memhub.get_debug_log() != 0 and self.__count__ == 0: + stdio.printf("[LISTDBG] append-first self=%llu data=%llu cnt=%llu cap=%llu es=%llu\n", + t.CUInt64T(self), t.CUInt64T(self.__data__), + t.CUInt64T(self.__count__), t.CUInt64T(self.__capacity__), + t.CUInt64T(self.__elem_size__)) if self.__count__ >= self.__capacity__: new_cap: t.CSizeT = self.__capacity__ * 2 new_data: t.CPtr = self.__pool__.alloc(new_cap * self.__elem_size__) diff --git a/includes/llvmlite/__init__.vp b/includes/llvmlite/__init__.vp index 9ee22bf..c5eb10d 100644 --- a/includes/llvmlite/__init__.vp +++ b/includes/llvmlite/__init__.vp @@ -149,7 +149,14 @@ def const_int(pool: memhub.MemBuddy | t.CPtr, bits: t.CInt, # 创建名字文本 name: t.CChar | t.CPtr = pool.alloc(32) if name is None: return None - viperlib.snprintf(name, 32, "%lld", val) + # LLVM i64 字面量范围不含 INT64_MIN(-9223372036854775808):该值必须 + # 用无符号位模式 9223372036854775808 表示(LLVM 接受),否则 opt 解析 + # "-9223372036854775808" 报 expected value token(二代编 viperlib.vp + # u_num=0x8000000000000000 崩溃根因;gen1/TPC 即输出无符号位模式)。 + if bits == 64 and val == -9223372036854775807 - 1: + viperlib.snprintf(name, 32, "9223372036854775808") + else: + viperlib.snprintf(name, 32, "%lld", val) return ConstInt(pool, ty, val, name) diff --git a/includes/memhub.vp b/includes/memhub.vp index ff540d4..a297f09 100644 --- a/includes/memhub.vp +++ b/includes/memhub.vp @@ -30,12 +30,43 @@ MEMBUDDY_HEADER_SIZE: t.CDefine = 8 # "崩溃点漂移/事发地遥远"变成"确定性定位到越界写发生的文件" MEMBUDDY_CANARY: t.CDefine = 8 +# 分配守卫(诊断,SlotsBugTest 二代编 list 头覆盖排查): +# alloc 时把用户数据区填充 0xCD 哨兵。若对象初始化(list.__init__ 等) +# 未执行,其字段保持 0xCDCD...,CTORDBG/VDBG 打印字段时一眼可辨 +# "未初始化(0xCDCD)" 与 "被覆盖(其他值)"。0=关闭(性能),1=开启。 +MEMBUDDY_FILL_GUARD: t.CDefine = 1 +MEMBUDDY_FILL_PATTERN: t.CDefine = 0xCD + def _canary_pattern() -> t.CUInt64T: """块尾 canary 值(0xA5A5A5A5A5A5A5A5,64 位)""" lo: t.CUInt64T = t.CUInt64T(0xA5A5A5A5) return (lo << 32) | lo +# [LISTDBG] 调试日志全局开关(默认关;命令行 --enable-debug-log 开启): +# list.__init__/append 的诊断 printf 输出量大,默认静默,仅排查时开启 +_g_debug_log: int = 0 + +def set_debug_log(flag: int) -> None: + """设置调试日志开关(1=开启 LISTDBG 诊断输出)""" + global _g_debug_log + _g_debug_log = flag + +def get_debug_log() -> int: + """读取调试日志开关(0=关,1=开)""" + return _g_debug_log + +# [ALLOCDBG] 分配者记录:当前正在翻译的文件 sha1(Phase1Main/Translator +# 每文件翻译前设置)。alloc size==48(list 对象大小)且 --enable-debug-log +# 开启时打印块地址+src,定位"未走 list.__init__ 的异常 list"创建者 +# (SlotsBugTest KwEntry cargs 只写 Data/IterIndex 的块归属)。 +_g_alloc_src: str = None + +def set_alloc_src(src: str) -> None: + """设置当前翻译文件 sha1(alloc 分配者记录用)""" + global _g_alloc_src + _g_alloc_src = src + def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT: if align == 0: return val return (val + align - 1) & ~(align - 1) @@ -579,6 +610,20 @@ class MemBuddy(MemManager): bs: t.CSizeT = _block_size_at_order(order) c.DerefAs(t.CVoid(t.CUInt64T(block) + bs - MEMBUDDY_CANARY, t.CPtr), t.CVoid(_canary_pattern(), t.CPtr)) + # 分配守卫:填充用户数据区 0xCD 哨兵(未初始化检测)。 + # 调用方初始化(list.__init__ 等)覆盖前,字段保持 0xCDCD... + # CTORDBG 打印 d0-d40 时:0xCDCD...=未初始化,其他=被覆盖。 + if MEMBUDDY_FILL_GUARD != 0: + fill_size: t.CSizeT = bs - MEMBUDDY_HEADER_SIZE - MEMBUDDY_CANARY + if fill_size > 0: + string.memset(result, MEMBUDDY_FILL_PATTERN, fill_size) + # [ALLOCDBG] 分配者记录:size==48(list 对象)且 --enable-debug-log + # 开启时打印 chk_stack 序号+块地址+当前翻译文件 src。序号与 + # CTORDBG 的 cargs_in_block=idx 匹配 → 精确定位未走 + # list.__init__ 的异常 list(如 KwEntry cargs)的分配点。 + if get_debug_log() != 0 and size == 48: + stdio.printf("[ALLOCDBG] alloc48 idx=%zu block=%llu ret=%llu src=%s\n", + self.chk_depth, t.CUInt64T(block), t.CUInt64T(result), _g_alloc_src) # 记录到 checkpoint 栈(供 reset_to 回收) # 栈满时 stdlib.realloc 翻倍扩容(防爆满后记录缺失 # → reset 不回收 + _is_valid_ptr 栈校验退化的连锁问题) @@ -605,8 +650,9 @@ class MemBuddy(MemManager): if size != 0 and self.usable is not None: needed2: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY order2: t.CInt = self._order_for_size(needed2) - stdio.printf("[MEM] alloc 失败 size=%zu needed=%zu order=%d max_order=%d used=%zu\n", - size, needed2, order2, self.max_order, self.used_bytes()) + stdio.printf("[MEM] alloc 失败 size=%zu needed=%zu order=%d max_order=%d used=%zu pool_base=%llu\n", + size, needed2, order2, self.max_order, self.used_bytes(), + t.CUInt64T(self.usable)) # 越界写诊断:free list 结构损坏(self_check!=0)说明有越界写穿 # 破坏块头/free list next 指针 → alloc 找不到块(used 虚高非真实耗尽) sc: t.CInt = self.self_check()