本文主要依据网上现有资料分析以下ASAN的相关源码。源码的调试分析放在续文中。
克隆一份源码(根目录llvm-project
,版本CommitID
0156f91f3b0a
,此时Clang版本为14)。
git clone --depth=1 https://github.com/llvm/llvm-project
查资料—Sanitizer注册
Sanitizer ID信息
Sanitizers.def
包含了ASAN的注册信息,Sanitizers.def
会在Sanitizers.h
的struct SanitizerKind
中导入(include
),也就是说Sanitizers.h
维护了注册信息的数据结构,Sanitizers.def
包含了注册信息的具体内容。
// clang\include\clang\Basic\Sanitizers.def
SANITIZER("address", Address)
Sanitizers.def
被clang\include\clang\Basic\Sanitizers.h
导入并解释。
Santizer参数信息
// clang\include\clang\Driver\SanitizerArgs.h
...
class SanitizerArgs {
...
bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); }
...
};
...
添加支持的Santizer ID(如果Santizer无需运行时支持,不含ASAN)
// clang\lib\Driver\ToolChain.cpp
SanitizerMask ToolChain::getSupportedSanitizers() const {...}
静态看ASAN源码结构
相关资料如AddressSanitizer算法及源码解析和LLVM每日谈之六 LLVM的源码结构过于简短。
ASAN主体内容位于llvm\lib\Transforms\Instrumentation\AddressSanitizer.{cpp, h}
。
AddressSanitizer.h
首先观察AddressSanitizer.h
,里面包含了ASanGlobalsMetadataAnalysis
(模块Pass)、AddressSanitizerPass
(函数Pass)和ModuleAddressSanitizerPass
(模块Pass),这三者继承自PassInfoMixin
,使用New PassManager,用到了称为静态多态的CRTP。(还包含了用于初始化构建LegacyPassSanitizer的函数createAddressSanitizerFunctionPass
和createModuleAddressSanitizerLegacyPassPass
)
ASanGlobalsMetadataAnalysis
负责处理全局元数据GlobalsMetadata
AddressSanitizerPass
通过struct AddressSanitizer
实现插桩任务ModuleAddressSanitizerPass
通过class ModuleAddressSanitizer
实现插桩任务。- (后两者会通过
ASanGlobalsMetadataAnalysis
获取全局元数据。)
AddressSanitizer.cpp
包含ASanGlobalsMetadataWrapperPass
模块Pass、AddressSanitizerLegacyPass
函数Pass、ModuleAddressSanitizerLegacyPass
模块Pass,使用Legacy PassManager。
ASanGlobalsMetadataWrapperPass
会处理全局元数据GlobalsMetadata
AddressSanitizerLegacyPass
通过AddressSanitizer
完成具体功能ModuleAddressSanitizerLegacyPass
通过ModuleAddressSanitizer
完成具体功能。- (后两者会通过
ASanGlobalsMetadataWrapperPass
获取全局元数据。)
Legacy Pass通过INITIALIZE_PASS
宏展开(如展开定义initializeAddressSanitizerLegacyPassPass()
,并间接被createAddressSanitizerFunctionPass
调用),用于注册对应Pass。
// llvm\lib\Transforms\Instrumentation\AddressSanitizer.cpp
INITIALIZE_PASS(ASanGlobalsMetadataWrapperPass, "asan-globals-md",
"Read metadata to mark which globals should be instrumented "
"when running ASan.",
false, true)
INITIALIZE_PASS_BEGIN(
AddressSanitizerLegacyPass, "asan",
"AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false,
false)
INITIALIZE_PASS_DEPENDENCY(ASanGlobalsMetadataWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(
AddressSanitizerLegacyPass, "asan",
"AddressSanitizer: detects use-after-free and out-of-bounds bugs.", false,
false)
INITIALIZE_PASS(
ModuleAddressSanitizerLegacyPass, "asan-module",
"AddressSanitizer: detects use-after-free and out-of-bounds bugs."
"ModulePass",
false, false)
后续
《LLVM ASAN【源码分析】(二)》描述了调试环境的搭建。
《LLVM ASAN【源码分析】(三)》中描述了gdb调试分析ASAN源码的内容。