feat(memhub,list,llvmlite): 0xCD 分配守卫、诊断开关与 INT64_MIN 常量修复 - memhub.vp alloc 填充 0xCD 哨兵 + set_debug_log/get_debug_log + ALLOCDBG 分配者记录; _list.vp __init__/append 诊断; llvmlite i64 INT64_MIN 输出无符号位模式(LLVM 拒绝 -9223372036854775808 字面量)。定位 SlotsBugTest KwEntry cargs use-after-free 与常量 dump 错误

This commit is contained in:
TermiNexus committed 2026-08-25 13:19:08 +08:00
1 parent c3a43dfe76
commit 3100bb9343
3 files changed
+77 -3

No files matched your search

+21
View File
@@ -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__)
+8 -1
View File
@@ -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)
+48 -2
View File
@@ -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()