fix(includes): ASan 集成支持 + 越界写封堵 + TypePrint 类型名截断 40→255

1. Phase2Translator 增加 TPC_ASAN 支持(opt asan 插桩+链接 -fsanitize=address),配合 clang64 定位 0xbe 崩溃。2. llvmlite/memhub/viperio/viperlib 多处理无界 strcpy/strcat/下溢/递归守卫/栈数组钳制。3. memhub alloc 块尾 canary(MEMBUDDY_CANARY)+check_alive_blocks 校验+chk_stack realloc 扩容。4. TypePrint Ptr(Struct) 类型名截断上限 40→255:含 sha1 前缀类型名(如 bbdf3bbd4c3bc28c.CONSOLE_SCREEN_BUFFER_INFO=42)被截断产生未定义类型引用(llc undefined type)。
This commit is contained in:
TermiNexus committed 2026-08-10 18:09:13 +08:00
1 parent cb557c84ce
commit d2d319eb21
10 files changed
+195 -49

No files matched your search

+38 -8
View File
@@ -160,6 +160,15 @@ class Phase2Translator:
self.linker_cmd = linker_cmd
self.linker_flags = linker_flags or []
self.linker_output = linker_output
# ASan 模式:TPC_ASAN=1 时对全部 .ll 做 opt -passes=asan 插桩并链接 libasan。
# 检测 stdlib 堆/栈/全局越界与垃圾指针(MemBuddy pool 内部由 canary 覆盖)。
# 注意:mingw64 的 clang 不提供 ASan runtime(libclang_rt.asan 缺失),
# 必须使用 clang64 环境(自带 asan_dynamic runtime),PATH 前置 clang64/bin。
self.asan_mode = os.environ.get('TPC_ASAN') == '1'
if self.asan_mode:
_clang64_bin = r'D:\msys64\clang64\bin'
if os.path.isdir(_clang64_bin):
os.environ['PATH'] = _clang64_bin + os.pathsep + os.environ.get('PATH', '')
self.slice_level = 3
self.sha1_map: dict[str, str] = {}
self.sig_files: dict[str, str] = {}
@@ -1185,6 +1194,29 @@ class Phase2Translator:
except Exception as e:
_vlog().warning(f" [警告] 解析包重导出失败 {init_pyi_path}: {e}")
def _llc_compile(self, ll_path: str, obj_path: str,
cwd: str | None = None) -> subprocess.CompletedProcess:
"""编译单个 .ll 为 obj。
ASan 模式(TPC_ASAN=1)下先对 IR 执行 opt -passes=asan 插桩:
检测 stdlib 堆/栈/全局越界写与垃圾指针解引用(MemBuddy pool 内部
由块尾 canary 覆盖,两者互补)。opt 失败返回其结果(returncode!=0)。
"""
compile_input = ll_path
if self.asan_mode:
asan_ll = ll_path[:-3] + '_asan.ll'
# -asan-globals=false:TPC 对全局变量(如各模块 _g_gen)用直接地址寻址,
# ASan 全局 redzone 重定位后引用错位会导致读到垃圾指针(如
# register_struct 的 self=0xbebebebe...)。先关闭全局插桩排除该因素。
opt_cmd = ['opt', '-passes=asan', '-asan-globals=false', ll_path, '-o', asan_ll]
opt_r = subprocess.run(opt_cmd, capture_output=True, text=True, cwd=cwd)
if opt_r.returncode != 0:
_vlog().error(f" opt ASan 插桩失败: {opt_r.stderr.strip()}")
return opt_r
compile_input = asan_ll
cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, compile_input]
return subprocess.run(cmd, capture_output=True, text=True, cwd=cwd)
def _compile_ll_files(self, active_sha1s: set[str]) -> None:
"""将 output_dir 中属于 active_sha1s 的 .ll 文件编译为 .obj(跳过已编译过的 include 文件)"""
# 第一次 walk:清理 stale 文件(.obj/.deps.json/纯 .ll,排除 .stub.ll/.text.ll)
@@ -1307,9 +1339,7 @@ class Phase2Translator:
f.write(opt_content)
merged_obj = os.path.join(self.output_dir, '_merged.obj')
try:
cmd = [self.compile_cmd] + self.compile_flags + ['-o', merged_obj, optimized_ll]
result = subprocess.run(cmd, capture_output=True, text=True,
cwd=self.output_dir)
result = self._llc_compile(optimized_ll, merged_obj, self.output_dir)
if result.returncode == 0:
_vlog().success(f" 合并模块编译完成")
for ll_path in ll_files:
@@ -1591,9 +1621,7 @@ class Phase2Translator:
dso_ll_path = ll_path[:-3] + '_dso.ll'
with open(dso_ll_path, 'w', encoding='utf-8') as f:
f.write(ll_content)
cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, dso_ll_path]
result = subprocess.run(cmd, capture_output=True, text=True,
cwd=os.path.dirname(ll_path) or '.')
result = self._llc_compile(dso_ll_path, obj_path, os.path.dirname(ll_path) or '.')
if result.returncode == 0:
return (rel, 'ok', '')
else:
@@ -2355,8 +2383,7 @@ class Phase2Translator:
def _compile_one_include(task):
dso_ll_path, obj_path = task[0], task[1]
cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, dso_ll_path]
result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.output_dir)
result = self._llc_compile(dso_ll_path, obj_path, self.output_dir)
return (task, result)
if len(compile_tasks) > 1:
@@ -3050,6 +3077,9 @@ SECTIONS {
# 其他所有标志(包括 -Wl, 选项)放在目标文件之前
non_lib_flags.append(flag)
i += 1
# ASan 模式:链接 libasan(配合各 .ll 的 opt -passes=asan 插桩)
if self.asan_mode:
non_lib_flags.append('-fsanitize=address')
cmd = [self.linker_cmd] + non_lib_flags + ['-o', link_output] + all_link_files + lib_flags
_vlog().info(f" 执行: {' '.join(cmd)}")
result = subprocess.run(