fix(build): ASan includes 缓存独立目录隔离
- Config: get_includes_binary_dir 支持可配置后缀(_inc_bin_suffix) - main: --asan 用 .binary_asan 独立缓存并清理,非 asan 复位 .binary - 修复 asan 插桩 obj 与非 asan obj 混链 → __asan_init undefined reference
This commit is contained in:
1 parent
b232c9266c
commit
1c7e8c2056
3 files changed
+38
-15
No files matched your search
@@ -40,6 +40,17 @@ StrictMode: t.CInt = 0
|
||||
IncludesDir: str = None # includes 目录路径(从 includes 数组首元素,兼容单目录场景)
|
||||
IncludesDirs: str = None # 全部 includes 目录(空格分隔,多 includes 目录支持)
|
||||
|
||||
# includes 预编译缓存目录后缀(asan 模式用 .binary_asan 隔离,避免
|
||||
# asan 插桩 obj 与非 asan obj 混链:asan obj 引用 __asan_init 等符号,
|
||||
# 非 asan 链接不提供 asan 库 → undefined reference)
|
||||
_inc_bin_suffix: str = ".binary"
|
||||
|
||||
|
||||
def set_inc_bin_suffix(suffix: str) -> None:
|
||||
"""设置 includes.binary 缓存目录后缀(如 ".binary_asan")"""
|
||||
global _inc_bin_suffix
|
||||
_inc_bin_suffix = suffix
|
||||
|
||||
|
||||
def Load_project_config(path: str) -> int:
|
||||
"""加载工程配置文件(project.vpj)
|
||||
@@ -451,17 +462,20 @@ def resolve_paths(project_dir: str) -> int:
|
||||
|
||||
|
||||
def get_includes_binary_dir() -> str:
|
||||
"""获取 includes.binary 目录路径(includes 目录 + .binary 后缀)
|
||||
"""获取 includes.binary 目录路径(includes 目录 + 缓存后缀)
|
||||
|
||||
includes 目录如 ../includes,则 includes.binary 为 ../includes.binary
|
||||
includes 目录如 ../includes,默认返回 ../includes.binary;
|
||||
asan 模式(set_inc_bin_suffix(".binary_asan"))返回 ../includes.binary_asan,
|
||||
隔离 asan 插桩 obj,避免与非 asan obj 混链。
|
||||
"""
|
||||
if IncludesDir is None:
|
||||
return None
|
||||
inc_len: t.CSizeT = string.strlen(IncludesDir)
|
||||
buf: str = _mbuddy.alloc(inc_len + 8)
|
||||
suf_len: t.CSizeT = string.strlen(_inc_bin_suffix)
|
||||
buf: str = _mbuddy.alloc(inc_len + suf_len + 1)
|
||||
if buf is None:
|
||||
return None
|
||||
viperlib.snprintf(buf, inc_len + 8, "%s.binary", IncludesDir)
|
||||
viperlib.snprintf(buf, inc_len + suf_len + 1, "%s%s", IncludesDir, _inc_bin_suffix)
|
||||
return buf
|
||||
|
||||
|
||||
|
||||
@@ -552,14 +552,18 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
||||
|
||||
# 构造命令: clang++ {obj_path} extra_objs -o {output_dir}/{linker_output} linker_flags
|
||||
# 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖
|
||||
# ASan 模式:追加 -fsanitize=address 链接 libasan(配合 opt 插桩)
|
||||
# ASan 模式:mingw64 clang 的 -fsanitize=address 在 mingw64/lib 下找不到
|
||||
# asan 运行库(实际在 clang64),改为显式链接 clang64 的 libclang_rt
|
||||
# (DLL 版,运行时需 D:/msys64/clang64/bin 在 PATH)
|
||||
use_flags: str = linker_flags
|
||||
if _asan_mode != 0:
|
||||
fl_len: t.CSizeT = string.strlen(linker_flags) + 32
|
||||
fl_len: t.CSizeT = string.strlen(linker_flags) + 256
|
||||
use_flags = _mbuddy.alloc(fl_len)
|
||||
if use_flags is None:
|
||||
return 1
|
||||
viperlib.snprintf(use_flags, fl_len, "%s -fsanitize=address", linker_flags)
|
||||
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)
|
||||
cmd_len: t.CSizeT = string.strlen(linker_cmd) + string.strlen(obj_path) + string.strlen(use_flags) + string.strlen(output_dir) + string.strlen(linker_output) + extra_len + 128
|
||||
cmd: bytes = _mbuddy.alloc(cmd_len)
|
||||
if cmd is None:
|
||||
@@ -671,14 +675,16 @@ 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 模式:追加 -fsanitize=address 链接 libasan(配合 opt 插桩)
|
||||
# ASan 模式:显式链接 clang64 的 libclang_rt(同 link_obj_to_exe)
|
||||
use_flags: str = linker_flags
|
||||
if _asan_mode != 0:
|
||||
fl_len: t.CSizeT = string.strlen(linker_flags) + 32
|
||||
fl_len: t.CSizeT = string.strlen(linker_flags) + 256
|
||||
use_flags = _mbuddy.alloc(fl_len)
|
||||
if use_flags is None:
|
||||
return 1
|
||||
viperlib.snprintf(use_flags, fl_len, "%s -fsanitize=address", linker_flags)
|
||||
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)
|
||||
cmd_len: t.CSizeT = string.strlen(linker_cmd) + obj_paths_len + string.strlen(use_flags) + string.strlen(linker_output) + extra_len + 128
|
||||
cmd: bytes = _mbuddy.alloc(cmd_len)
|
||||
if cmd is None:
|
||||
|
||||
+8
-5
@@ -236,23 +236,26 @@ def main() -> int:
|
||||
|
||||
stdio.printf("\n参数解析完成。\n")
|
||||
|
||||
# ASan 模式:设置 BuildPipeline 全局标志(compile_ll_to_obj 先 opt 插桩,链接加 -fsanitize=address)
|
||||
# ASan 模式:设置 BuildPipeline 全局标志(compile_ll_to_obj 先 opt 插桩,链接 asan 库)
|
||||
# includes 缓存用独立目录 .binary_asan 隔离 asan 插桩 obj,避免与非 asan obj 混链
|
||||
# (asan obj 引用 __asan_init 等符号,非 asan 链接不提供 asan 库 → undefined reference)
|
||||
if args.get_bool("asan"):
|
||||
BuildPipeline.set_asan_mode(1)
|
||||
Config.set_inc_bin_suffix(".binary_asan")
|
||||
if log is not None:
|
||||
log.info("ASan 模式已启用(opt -passes=asan + -fsanitize=address)", "asan")
|
||||
# ASan 模式强制重建 includes.binary:缓存 obj 未做 asan 插桩,
|
||||
# 与非 asan obj 混链会导致 ASan 运行时崩溃
|
||||
log.info("ASan 模式已启用(opt -passes=asan + libclang_rt)", "asan")
|
||||
# ASan 模式清理 asan includes 缓存(强制重建 asan 插桩 obj)
|
||||
mf_inc_bin_asan: str = Config.get_includes_binary_dir()
|
||||
if mf_inc_bin_asan is not None:
|
||||
n_asan: int = Utils.CleanDir(mf_inc_bin_asan)
|
||||
if log is not None:
|
||||
fb_asan: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_asan is not None:
|
||||
viperlib.snprintf(fb_asan, 1024, "ASan 模式清理 includes.binary: %d 个文件(将重建 asan obj)", n_asan)
|
||||
viperlib.snprintf(fb_asan, 1024, "ASan 模式清理 includes 缓存: %d 个文件(将重建 asan obj)", n_asan)
|
||||
log.info(fb_asan, "asan")
|
||||
else:
|
||||
BuildPipeline.set_asan_mode(0)
|
||||
Config.set_inc_bin_suffix(".binary")
|
||||
|
||||
# 加载 project.vpj 配置
|
||||
proj_loaded: int = 0
|
||||
|
||||
Reference in new issue
Block a user