11 def get_required_attr(config
, attr_name
):
12 attr_value
= getattr(config
, attr_name
, None)
13 if attr_value
== None:
15 "No attribute %r in test configuration! You may need to run "
16 "tests from your build directory or add this attribute "
17 "to lit.site.cfg.py " % attr_name
22 config
.name
= "AddressSanitizer" + config
.name_suffix
24 # Platform-specific default ASAN_OPTIONS for lit tests.
25 default_asan_opts
= list(config
.default_sanitizer_opts
)
27 # On Darwin, leak checking is not enabled by default. Enable on macOS
28 # tests to prevent regressions
29 if config
.host_os
== "Darwin" and config
.apple_platform
== "osx":
30 default_asan_opts
+= ["detect_leaks=1"]
32 default_asan_opts_str
= ":".join(default_asan_opts
)
33 if default_asan_opts_str
:
34 config
.environment
["ASAN_OPTIONS"] = default_asan_opts_str
35 default_asan_opts_str
+= ":"
36 config
.substitutions
.append(
37 ("%env_asan_opts=", "env ASAN_OPTIONS=" + default_asan_opts_str
)
41 config
.test_source_root
= os
.path
.dirname(__file__
)
43 if config
.host_os
not in ["FreeBSD", "NetBSD"]:
48 # GCC-ASan doesn't link in all the necessary libraries automatically, so
49 # we have to do it ourselves.
50 if config
.compiler_id
== "GNU":
51 extra_link_flags
= ["-pthread", "-lstdc++", libdl_flag
]
55 # Setup default compiler flags used with -fsanitize=address option.
56 # FIXME: Review the set of required flags and check if it can be reduced.
57 target_cflags
= [get_required_attr(config
, "target_cflags")] + extra_link_flags
58 target_cxxflags
= config
.cxx_mode_flags
+ target_cflags
59 clang_asan_static_cflags
= (
62 "-mno-omit-leaf-frame-pointer",
63 "-fno-omit-frame-pointer",
64 "-fno-optimize-sibling-calls",
66 + config
.debug_info_flags
69 if config
.target_arch
== "s390x":
70 clang_asan_static_cflags
.append("-mbackchain")
71 clang_asan_static_cxxflags
= config
.cxx_mode_flags
+ clang_asan_static_cflags
73 target_is_msvc
= bool(re
.match(r
".*-windows-msvc$", config
.target_triple
))
75 asan_dynamic_flags
= []
76 if config
.asan_dynamic
:
77 asan_dynamic_flags
= ["-shared-libasan"]
78 if platform
.system() == "Windows" and target_is_msvc
:
79 # On MSVC target, we need to simulate "clang-cl /MD" on the clang driver side.
80 asan_dynamic_flags
+= [
83 "-Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames",
85 elif platform
.system() == "FreeBSD":
86 # On FreeBSD, we need to add -pthread to ensure pthread functions are available.
87 asan_dynamic_flags
+= ["-pthread"]
88 config
.available_features
.add("asan-dynamic-runtime")
90 config
.available_features
.add("asan-static-runtime")
91 clang_asan_cflags
= clang_asan_static_cflags
+ asan_dynamic_flags
92 clang_asan_cxxflags
= clang_asan_static_cxxflags
+ asan_dynamic_flags
94 # Add win32-(static|dynamic)-asan features to mark tests as passing or failing
95 # in those modes. lit doesn't support logical feature test combinations.
96 if platform
.system() == "Windows":
97 if config
.asan_dynamic
:
98 win_runtime_feature
= "win32-dynamic-asan"
100 win_runtime_feature
= "win32-static-asan"
101 config
.available_features
.add(win_runtime_feature
)
104 def build_invocation(compile_flags
):
105 return " " + " ".join([config
.clang
] + compile_flags
) + " "
108 config
.substitutions
.append(("%clang ", build_invocation(target_cflags
)))
109 config
.substitutions
.append(("%clangxx ", build_invocation(target_cxxflags
)))
110 config
.substitutions
.append(("%clang_asan ", build_invocation(clang_asan_cflags
)))
111 config
.substitutions
.append(("%clangxx_asan ", build_invocation(clang_asan_cxxflags
)))
112 if config
.asan_dynamic
:
113 if config
.host_os
in ["Linux", "FreeBSD", "NetBSD", "SunOS"]:
114 shared_libasan_path
= os
.path
.join(
115 config
.compiler_rt_libdir
,
116 "libclang_rt.asan{}.so".format(config
.target_suffix
),
118 elif config
.host_os
== "Darwin":
119 shared_libasan_path
= os
.path
.join(
120 config
.compiler_rt_libdir
,
121 "libclang_rt.asan_{}_dynamic.dylib".format(config
.apple_platform
),
125 "%shared_libasan substitution not set but dynamic ASan is available."
127 shared_libasan_path
= None
129 if shared_libasan_path
is not None:
130 config
.substitutions
.append(("%shared_libasan", shared_libasan_path
))
131 config
.substitutions
.append(
132 ("%clang_asan_static ", build_invocation(clang_asan_static_cflags
))
134 config
.substitutions
.append(
135 ("%clangxx_asan_static ", build_invocation(clang_asan_static_cxxflags
))
138 if platform
.system() == "Windows":
139 # MSVC-specific tests might also use the clang-cl.exe driver.
141 clang_cl_cxxflags
= [
142 "-Wno-deprecated-declarations",
144 "-D_HAS_EXCEPTIONS=0",
147 clang_cl_asan_cxxflags
= ["-fsanitize=address"] + clang_cl_cxxflags
148 if config
.asan_dynamic
:
149 clang_cl_asan_cxxflags
.append("-MD")
151 clang_cl_invocation
= build_invocation(clang_cl_cxxflags
)
152 clang_cl_invocation
= clang_cl_invocation
.replace("clang.exe", "clang-cl.exe")
153 config
.substitutions
.append(("%clang_cl ", clang_cl_invocation
))
155 clang_cl_asan_invocation
= build_invocation(clang_cl_asan_cxxflags
)
156 clang_cl_asan_invocation
= clang_cl_asan_invocation
.replace(
157 "clang.exe", "clang-cl.exe"
159 config
.substitutions
.append(("%clang_cl_asan ", clang_cl_asan_invocation
))
160 config
.substitutions
.append(("%clang_cl_nocxx_asan ", clang_cl_asan_invocation
))
161 config
.substitutions
.append(("%Od", "-Od"))
162 config
.substitutions
.append(("%Fe", "-Fe"))
163 config
.substitutions
.append(("%LD", "-LD"))
164 config
.substitutions
.append(("%MD", "-MD"))
165 config
.substitutions
.append(("%MT", "-MT"))
166 config
.substitutions
.append(("%Gw", "-Gw"))
168 base_lib
= os
.path
.join(
169 config
.compiler_rt_libdir
, "clang_rt.asan%%s%s.lib" % config
.target_suffix
171 config
.substitutions
.append(("%asan_lib", base_lib
% ""))
172 config
.substitutions
.append(("%asan_cxx_lib", base_lib
% "_cxx"))
173 config
.substitutions
.append(("%asan_dll_thunk", base_lib
% "_dll_thunk"))
175 # To make some of these tests work on MinGW target without changing their
176 # behaviour for MSVC target, substitute clang-cl flags with gcc-like ones.
177 config
.substitutions
.append(("%clang_cl ", build_invocation(target_cxxflags
)))
178 config
.substitutions
.append(
179 ("%clang_cl_asan ", build_invocation(clang_asan_cxxflags
))
181 config
.substitutions
.append(
182 ("%clang_cl_nocxx_asan ", build_invocation(clang_asan_cflags
))
184 config
.substitutions
.append(("%Od", "-O0"))
185 config
.substitutions
.append(("%Fe", "-o"))
186 config
.substitutions
.append(("%LD", "-shared"))
187 config
.substitutions
.append(("%MD", ""))
188 config
.substitutions
.append(("%MT", ""))
189 config
.substitutions
.append(("%Gw", "-fdata-sections"))
191 # FIXME: De-hardcode this path.
192 asan_source_dir
= os
.path
.join(
193 get_required_attr(config
, "compiler_rt_src_root"), "lib", "asan"
195 python_exec
= shlex
.quote(get_required_attr(config
, "python_executable"))
196 # Setup path to asan_symbolize.py script.
197 asan_symbolize
= os
.path
.join(asan_source_dir
, "scripts", "asan_symbolize.py")
198 if not os
.path
.exists(asan_symbolize
):
199 lit_config
.fatal("Can't find script on path %r" % asan_symbolize
)
200 config
.substitutions
.append(
201 ("%asan_symbolize", python_exec
+ " " + asan_symbolize
+ " ")
203 # Setup path to sancov.py script.
204 sanitizer_common_source_dir
= os
.path
.join(
205 get_required_attr(config
, "compiler_rt_src_root"), "lib", "sanitizer_common"
207 sancov
= os
.path
.join(sanitizer_common_source_dir
, "scripts", "sancov.py")
208 if not os
.path
.exists(sancov
):
209 lit_config
.fatal("Can't find script on path %r" % sancov
)
210 config
.substitutions
.append(("%sancov ", python_exec
+ " " + sancov
+ " "))
212 # Determine kernel bitness
213 if config
.host_arch
.find("64") != -1 and not config
.android
:
218 config
.substitutions
.append(
219 ("CHECK-%kernel_bits", ("CHECK-kernel-" + kernel_bits
+ "-bits"))
222 config
.substitutions
.append(("%libdl", libdl_flag
))
224 config
.available_features
.add("asan-" + config
.bits
+ "-bits")
226 # Fast unwinder doesn't work with Thumb
227 if not config
.arm_thumb
:
228 config
.available_features
.add("fast-unwinder-works")
230 # Turn on leak detection on 64-bit Linux.
231 leak_detection_android
= (
233 and "android-thread-properties-api" in config
.available_features
234 and (config
.target_arch
in ["x86_64", "i386", "i686", "aarch64"])
236 leak_detection_linux
= (
237 (config
.host_os
== "Linux")
238 and (not config
.android
)
239 and (config
.target_arch
in ["x86_64", "i386", "riscv64", "loongarch64"])
241 leak_detection_mac
= (config
.host_os
== "Darwin") and (config
.apple_platform
== "osx")
242 leak_detection_netbsd
= (config
.host_os
== "NetBSD") and (
243 config
.target_arch
in ["x86_64", "i386"]
246 leak_detection_android
247 or leak_detection_linux
248 or leak_detection_mac
249 or leak_detection_netbsd
251 config
.available_features
.add("leak-detection")
253 # Add the RT libdir to PATH directly so that we can successfully run the gtest
254 # binary to list its tests.
255 if config
.host_os
== "Windows" and config
.asan_dynamic
:
256 os
.environ
["PATH"] = os
.path
.pathsep
.join(
257 [config
.compiler_rt_libdir
, os
.environ
.get("PATH", "")]
260 # Default test suffixes.
261 config
.suffixes
= [".c", ".cpp"]
263 if config
.host_os
== "Darwin":
264 config
.suffixes
.append(".mm")
266 if config
.host_os
== "Windows":
267 config
.substitutions
.append(("%fPIC", ""))
268 config
.substitutions
.append(("%fPIE", ""))
269 config
.substitutions
.append(("%pie", ""))
271 config
.substitutions
.append(("%fPIC", "-fPIC"))
272 config
.substitutions
.append(("%fPIE", "-fPIE"))
273 config
.substitutions
.append(("%pie", "-pie"))
275 # Only run the tests on supported OSs.
276 if config
.host_os
not in ["Linux", "Darwin", "FreeBSD", "SunOS", "Windows", "NetBSD"]:
277 config
.unsupported
= True
279 if not config
.parallelism_group
:
280 config
.parallelism_group
= "shadow-memory"
282 if config
.host_os
== "NetBSD":
283 config
.substitutions
.insert(0, ("%run", config
.netbsd_noaslr_prefix
))