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:
1 parent
c3a43dfe76
commit
3100bb9343
3 files changed
+77
-3
No files matched your search
@@ -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__)
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
Reference in new issue
Block a user