refactor(asan): ASan 运行库目录改为按 PATH 自动探测,去除本机硬编码路径
- _FindAsanRuntimeDir() 重写为 _FindAsanRuntime():遍历 PATH 定位 - clang64/bin 由前置改为追加到 PATH,避免裸名 clang++/llc/opt 被解析到 clang64 的 libc++ 版本 - 缺失 ASan 运行库时的报错文案改用占位符路径
This commit is contained in:
1 parent
305242aa8a
commit
64f3d79b64
1 file changed
+47
-25
@@ -105,8 +105,11 @@ def _InvalidateTextCache(path: str) -> None:
|
||||
_TextReadCacheBytes -= len(_old)
|
||||
|
||||
|
||||
def _FindAsanRuntimeDir() -> str | None:
|
||||
"""定位 clang64 的 ASan 运行库目录(按 LLVM 大版本取最新的那个)
|
||||
_ASAN_DLL_A = 'libclang_rt.asan_dynamic-x86_64.dll.a'
|
||||
|
||||
|
||||
def _FindAsanRuntime() -> tuple[str, str] | None:
|
||||
"""通过 PATH 定位 clang64 的 ASan 运行库(按 LLVM 大版本取最新的那个)
|
||||
|
||||
mingw64 的 clang 只为 x86_64-w64-windows-gnu 目标提供 builtins / fuzzer /
|
||||
profile / orc 运行库,**没有 ASan runtime**(<resource-dir>/lib/
|
||||
@@ -116,27 +119,39 @@ def _FindAsanRuntimeDir() -> str | None:
|
||||
clang64(MSVC ABI) 那边才有 libclang_rt.asan_dynamic-x86_64.dll.a 与
|
||||
libclang_rt.asan_dynamic_runtime_thunk-x86_64.a,只能借用这两份。
|
||||
|
||||
路径**不再写死**:遍历 PATH 的每个目录 E,按 `E` 与 `dirname(E)` 两种可能取 base,
|
||||
拼出 `<base>/lib/clang/<大版本>/lib/windows`,命中即为链接库目录;对应的运行期
|
||||
DLL 目录取 `<base>/bin`。
|
||||
|
||||
Returns:
|
||||
形如 D:\\msys64\\clang64\\lib\\clang\\22\\lib\\windows 的目录;找不到返回 None
|
||||
(链接库目录, 运行期 DLL 目录);都找不到返回 None
|
||||
"""
|
||||
root = r'D:\msys64\clang64\lib\clang'
|
||||
if not os.path.isdir(root):
|
||||
return None
|
||||
found: list[str] = []
|
||||
for name in os.listdir(root):
|
||||
cand = os.path.join(root, name, 'lib', 'windows')
|
||||
if os.path.isfile(os.path.join(cand, 'libclang_rt.asan_dynamic-x86_64.dll.a')):
|
||||
found.append(cand)
|
||||
if not found:
|
||||
hits: list[tuple[str, str]] = []
|
||||
seen: set[str] = set()
|
||||
for entry in os.environ.get('PATH', '').split(os.pathsep):
|
||||
if not entry:
|
||||
continue
|
||||
for base in (entry, os.path.dirname(entry)):
|
||||
if not base:
|
||||
continue
|
||||
root = os.path.join(base, 'lib', 'clang')
|
||||
if root in seen or not os.path.isdir(root):
|
||||
continue
|
||||
seen.add(root)
|
||||
for name in os.listdir(root):
|
||||
cand = os.path.join(root, name, 'lib', 'windows')
|
||||
if os.path.isfile(os.path.join(cand, _ASAN_DLL_A)):
|
||||
hits.append((cand, os.path.join(base, 'bin')))
|
||||
if not hits:
|
||||
return None
|
||||
|
||||
def _Ver(path: str) -> int:
|
||||
def _Ver(item: tuple[str, str]) -> int:
|
||||
# 目录名是 LLVM 大版本号(如 "22")——按数值比,否则 "9" 会排在 "22" 之后
|
||||
v = path.split(os.sep)[-3]
|
||||
v = item[0].split(os.sep)[-3]
|
||||
return int(v) if v.isdigit() else 0
|
||||
|
||||
found.sort(key=_Ver)
|
||||
return found[-1]
|
||||
hits.sort(key=_Ver)
|
||||
return hits[-1]
|
||||
|
||||
|
||||
# ---------- --traceback:地址→源行 旁文件(<exe>.stackmap)----------
|
||||
@@ -1234,15 +1249,20 @@ class Phase2Translator:
|
||||
# 环境变量在 worker 子进程/外部调用链下不可靠)。
|
||||
# 检测 stdlib 堆/栈/全局越界与垃圾指针(MemBuddy pool 内部由 canary 覆盖)。
|
||||
# 注意:mingw64 的 clang 不提供 x86_64-w64-windows-gnu 目标的 ASan runtime,
|
||||
# 只能借用 clang64(MSVC ABI) 的那两份:PATH 前置 clang64/bin(运行期 DLL),
|
||||
# 链接时显式 -l: 那两份 .a/.dll.a(见 _FindAsanRuntimeDir 的说明)。
|
||||
# 只能借用 clang64(MSVC ABI) 的那两份:PATH 末尾追加 clang64/bin(运行期 DLL),
|
||||
# 链接时显式 -l: 那两份 .a/.dll.a(见 _FindAsanRuntime 的说明)。
|
||||
self.asan_mode = asan_mode
|
||||
self.asan_rt_dir: str | None = None
|
||||
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.asan_rt_dir = _FindAsanRuntimeDir()
|
||||
_rt = _FindAsanRuntime()
|
||||
if _rt is not None:
|
||||
self.asan_rt_dir, _asan_bin = _rt
|
||||
# clang64/bin 必须**追加**到 PATH 末尾:既要让运行期能找到
|
||||
# libclang_rt.asan_dynamic-x86_64.dll,又不能前置 —— 前置会让裸名
|
||||
# clang++.exe / llc / opt 解析到 clang64 的 libc++ 版本,与 includes/
|
||||
# 里 mingw64(libstdc++) 编的静态库链接不上。
|
||||
if _asan_bin and os.path.isdir(_asan_bin):
|
||||
os.environ['PATH'] = os.environ.get('PATH', '') + os.pathsep + _asan_bin
|
||||
self.slice_level = 3
|
||||
# 函数级 DWARF 调试元数据(--dwarf;--asan 时自动开启):False=未启用
|
||||
# (零影响,不构造任何 DI 元数据);True=App 源模块的 .ll 携带
|
||||
@@ -4905,9 +4925,11 @@ SECTIONS {
|
||||
if self.asan_mode:
|
||||
if self.asan_rt_dir is None:
|
||||
_vlog().error(
|
||||
"ASan 模式找不到 clang64 的 ASan 运行库目录 "
|
||||
r"(D:\msys64\clang64\lib\clang\<ver>\lib\windows)\n"
|
||||
" 请确认 msys2 的 mingw-w64-clang-x86_64-compiler-rt 已安装。")
|
||||
"ASan 模式在 PATH 里找不到 clang64 的 ASan 运行库目录 "
|
||||
"(<MSYS2>\\clang64\\lib\\clang\\<ver>\\lib\\windows\\"
|
||||
"libclang_rt.asan_dynamic-x86_64.dll.a)\n"
|
||||
" 请确认 msys2 的 mingw-w64-clang-x86_64-compiler-rt 已安装,"
|
||||
"且 <MSYS2>\\clang64(或其 bin)已在 PATH 中。")
|
||||
sys.exit(1)
|
||||
lib_flags.append('-L' + self.asan_rt_dir)
|
||||
lib_flags.append('-l:libclang_rt.asan_dynamic-x86_64.dll.a')
|
||||
|
||||
Reference in new issue
Block a user