fix(tpv): ASan 运行库改由 project.vpj 声明; read_all 容量语义修正与超限源文件 fail-fast

- --asan: 移除 BuildPipeline 中硬编码的 clang64 libclang_rt 注入, 改由工程在 linker.static_libs / dynamic_libs / flags 中自行声明; 新增 Config.asan_runtime_declared(), main.vp 在未声明时 fail-fast 并列出所需运行库, 不再给含混的 undefined reference
- read_all: 容量参数含终止符(最多读 cap-1 字节), 故删除 12 处恒不可达的 else 截断兜底; 并在读取前按 f.size() fail-fast 拒绝超限源文件(main.vp / BuildPipeline / Phase1Main / Phase1Scan / Phase2), 避免静默截断后报出莫名其妙的语法错误
- project.vpj(根 / Test / NegativeTest / Sha1Test): linker.cmd 由裸 clang++ 改为绝对路径并补 -fuse-ld=lld
This commit is contained in:
TermiNexus committed 2026-09-10 22:33:18 +08:00
1 parent 76f03b5987
commit a5260f4441
18 files changed
+119 -97

No files matched your search

+16 -23
View File
@@ -36,7 +36,8 @@ import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
# 全局 mbuddy 指针
_mbuddy: memhub.MemBuddy | t.CPtr
# ASan 模式(--asan):对 .ll 先 opt -passes=asan 插桩,链接加 -fsanitize=address
# ASan 模式(--asan):对 .ll 先 opt -passes=asan 插桩;ASan 运行库由
# project.vpj 的 linker.static_libs / dynamic_libs 显式声明(TPV 不注入)
_asan_mode: bool = 0
# --phase2command xxx.bat:不执行 llc/链接命令,只把 Phase B/B+/C 的
@@ -84,6 +85,12 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
if file_path is None: return None
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
if f.closed: return None
# read_all 的容量参数含终止符(最多读 cap-1 字节), 文件更长会被**静默截断**;
# 这里先按文件大小拒绝, 否则拿截断后的源码去 parse 只会得到莫名其妙的语法错误
if f.size() >= SRC_BUF_SIZE:
VLogger.error(f"源文件超过 {SRC_BUF_SIZE} 字节上限, 拒绝读取: {file_path}", "fileio")
f.close()
return None
src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE)
if src_buf is None:
f.close()
@@ -95,8 +102,6 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
return None
if bytes_read < SRC_BUF_SIZE:
src_buf[bytes_read] = 0
else:
src_buf[SRC_BUF_SIZE - 1] = 0
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
ast._lexer_init(lx, src_buf, mb)
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
@@ -760,18 +765,13 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
# 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖
# linker_static_libs / linker_dynamic_libs(project.vpj 显式指定的 .a/.obj/.dll/.so)
# 同样位于 -l 之前;动态库作为输入文件由 GNU ld 提取导入符号
# ASan 模式:mingw64 clang 的 -fsanitize=address 在 mingw64/lib 下找不到
# asan 运行库(实际在 clang64),改为显式链接 clang64 的 libclang_rt
# (DLL 版,运行时需 D:/msys64/clang64/bin 在 PATH)
# ASan 模式:ASan 运行库**不再**由 TPV 硬编码。clang 没有给
# x86_64-w64-windows-gnu 出 ASan 运行库,只能借用 clang64(MSVC ABI) 的
# libclang_rt,但那是工程级选择(且会牵进 MSVC 专有的 .drectve 指令),
# 不该由所有工程无条件承担 —— 改由 project.vpj 的
# linker.static_libs / linker.dynamic_libs 显式声明,main.vp 在 --asan
# 下会用 Config.asan_runtime_declared 校验是否声明过。
use_flags: str = linker_flags
if _asan_mode != 0:
fl_len: t.CSizeT = len(linker_flags) + 256
use_flags = _mbuddy.alloc(fl_len)
if use_flags is None:
return 1
viperlib.snprintf(use_flags, fl_len,
"%s -L D:/msys64/clang64/lib/clang/22/lib/windows -l:libclang_rt.asan_dynamic-x86_64.dll.a -l:libclang_rt.asan_dynamic_runtime_thunk-x86_64.a",
linker_flags)
static_libs: str = linker_static_libs
if static_libs is None:
static_libs = ""
@@ -1009,16 +1009,9 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT,
extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE)
# 构造命令: clang++ obj_paths extra_objs -o linker_output linker_flags
# ASan 模式:显式链接 clang64 的 libclang_rt(同 link_obj_to_exe)
# ASan 运行库同样不再由 TPV 注入(在 link_obj_to_exe 里已有说明):
# 由 project.vpj 声明,--asan 下由 main.vp 校验。
use_flags: str = linker_flags
if _asan_mode != 0:
fl_len: t.CSizeT = len(linker_flags) + 256
use_flags = _mbuddy.alloc(fl_len)
if use_flags is None:
return 1
viperlib.snprintf(use_flags, fl_len,
"%s -L D:/msys64/clang64/lib/clang/22/lib/windows -l:libclang_rt.asan_dynamic-x86_64.dll.a -l:libclang_rt.asan_dynamic_runtime_thunk-x86_64.a",
linker_flags)
static_libs2: str = linker_static_libs
if static_libs2 is None:
static_libs2 = ""