337 lines · python
1# -*- Python -*-2 3import os4import platform5import re6import shlex7 8import lit.formats9 10 11def get_required_attr(config, attr_name):12 attr_value = getattr(config, attr_name, None)13 if attr_value is None:14 lit_config.fatal(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_name18 )19 return attr_value20 21# Setup config name.22config.name = "AddressSanitizer" + config.name_suffix23 24# Platform-specific default ASAN_OPTIONS for lit tests.25default_asan_opts = list(config.default_sanitizer_opts)26 27# On Darwin, leak checking is not enabled by default. Enable on macOS28# tests to prevent regressions.29# Currently, detect_leaks for asan tests only work on Intel MacOS.30if (31 config.target_os == "Darwin"32 and config.apple_platform == "osx"33 and config.target_arch == "x86_64"34):35 default_asan_opts += ["detect_leaks=1"]36 37default_asan_opts_str = ":".join(default_asan_opts)38if default_asan_opts_str:39 config.environment["ASAN_OPTIONS"] = default_asan_opts_str40 default_asan_opts_str += ":"41config.substitutions.append(42 ("%env_asan_opts=", "env ASAN_OPTIONS=" + default_asan_opts_str)43)44config.substitutions.append(45 ("%export_asan_opts=", "export ASAN_OPTIONS=" + default_asan_opts_str)46)47 48# Setup source root.49config.test_source_root = os.path.dirname(__file__)50 51if config.target_os not in ["FreeBSD", "NetBSD"]:52 libdl_flag = "-ldl"53else:54 libdl_flag = ""55 56# GCC-ASan doesn't link in all the necessary libraries automatically, so57# we have to do it ourselves.58if config.compiler_id == "GNU":59 extra_link_flags = ["-pthread", "-lstdc++", libdl_flag]60else:61 extra_link_flags = []62 63# Setup default compiler flags used with -fsanitize=address option.64# FIXME: Review the set of required flags and check if it can be reduced.65target_cflags = [get_required_attr(config, "target_cflags")] + extra_link_flags66target_cxxflags = config.cxx_mode_flags + target_cflags67clang_asan_static_cflags = (68 [69 "-fsanitize=address",70 "-mno-omit-leaf-frame-pointer",71 "-fno-omit-frame-pointer",72 "-fno-optimize-sibling-calls",73 ]74 + config.debug_info_flags75 + target_cflags76)77if config.target_arch == "s390x":78 clang_asan_static_cflags.append("-mbackchain")79clang_asan_static_cxxflags = config.cxx_mode_flags + clang_asan_static_cflags80 81target_is_msvc = bool(re.match(r".*-windows-msvc$", config.target_triple))82 83asan_dynamic_flags = []84if config.asan_dynamic:85 asan_dynamic_flags = ["-shared-libasan"]86 if platform.system() == "Windows" and target_is_msvc:87 # On MSVC target, we need to simulate "clang-cl /MD" on the clang driver side.88 asan_dynamic_flags += [89 "-D_MT",90 "-D_DLL",91 "-Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames",92 ]93 elif platform.system() == "FreeBSD":94 # On FreeBSD, we need to add -pthread to ensure pthread functions are available.95 asan_dynamic_flags += ["-pthread"]96 config.available_features.add("asan-dynamic-runtime")97else:98 config.available_features.add("asan-static-runtime")99clang_asan_cflags = clang_asan_static_cflags + asan_dynamic_flags100clang_asan_cxxflags = clang_asan_static_cxxflags + asan_dynamic_flags101 102# Add win32-(static|dynamic)-asan features to mark tests as passing or failing103# in those modes. lit doesn't support logical feature test combinations.104if platform.system() == "Windows":105 if config.asan_dynamic:106 win_runtime_feature = "win32-dynamic-asan"107 else:108 win_runtime_feature = "win32-static-asan"109 config.available_features.add(win_runtime_feature)110 111 112def build_invocation(compile_flags, with_lto=False):113 lto_flags = []114 if with_lto and config.lto_supported:115 lto_flags += config.lto_flags116 117 return " " + " ".join([config.clang] + lto_flags + compile_flags) + " "118 119 120config.substitutions.append(("%clang ", build_invocation(target_cflags)))121config.substitutions.append(("%clangxx ", build_invocation(target_cxxflags)))122config.substitutions.append(("%clang_asan ", build_invocation(clang_asan_cflags)))123config.substitutions.append(("%clangxx_asan ", build_invocation(clang_asan_cxxflags)))124config.substitutions.append(125 ("%clang_asan_lto ", build_invocation(clang_asan_cflags, True))126)127config.substitutions.append(128 ("%clangxx_asan_lto ", build_invocation(clang_asan_cxxflags, True))129)130if config.asan_dynamic:131 if config.target_os in ["Linux", "FreeBSD", "NetBSD", "SunOS"]:132 shared_libasan_path = os.path.join(133 config.compiler_rt_libdir,134 "libclang_rt.asan{}.so".format(config.target_suffix),135 )136 elif config.target_os == "Darwin":137 shared_libasan_path = os.path.join(138 config.compiler_rt_libdir,139 "libclang_rt.asan_{}_dynamic.dylib".format(config.apple_platform),140 )141 elif config.target_os == "Windows":142 shared_libasan_path = os.path.join(143 config.compiler_rt_libdir,144 "clang_rt.asan_dynamic-{}.lib".format(config.target_suffix),145 )146 else:147 lit_config.warning(148 "%shared_libasan substitution not set but dynamic ASan is available."149 )150 shared_libasan_path = None151 152 if shared_libasan_path is not None:153 config.substitutions.append(("%shared_libasan", shared_libasan_path))154 config.substitutions.append(155 ("%clang_asan_static ", build_invocation(clang_asan_static_cflags))156 )157 config.substitutions.append(158 ("%clangxx_asan_static ", build_invocation(clang_asan_static_cxxflags))159 )160 161if platform.system() == "Windows":162 # MSVC-specific tests might also use the clang-cl.exe driver.163 if target_is_msvc:164 clang_cl_cxxflags = (165 [166 "-WX",167 "-D_HAS_EXCEPTIONS=0",168 ]169 + config.debug_info_flags170 + target_cflags171 )172 if config.compiler_id != "MSVC":173 clang_cl_cxxflags = ["-Wno-deprecated-declarations"] + clang_cl_cxxflags174 clang_cl_asan_cxxflags = ["-fsanitize=address"] + clang_cl_cxxflags175 if config.asan_dynamic:176 clang_cl_asan_cxxflags.append("-MD")177 178 clang_cl_invocation = build_invocation(clang_cl_cxxflags)179 clang_cl_invocation = clang_cl_invocation.replace("clang.exe", "clang-cl.exe")180 config.substitutions.append(("%clang_cl ", clang_cl_invocation))181 182 clang_cl_asan_invocation = build_invocation(clang_cl_asan_cxxflags)183 clang_cl_asan_invocation = clang_cl_asan_invocation.replace(184 "clang.exe", "clang-cl.exe"185 )186 config.substitutions.append(("%clang_cl_asan ", clang_cl_asan_invocation))187 config.substitutions.append(("%clang_cl_nocxx_asan ", clang_cl_asan_invocation))188 config.substitutions.append(("%Od", "-Od"))189 config.substitutions.append(("%Fe", "-Fe"))190 config.substitutions.append(("%LD", "-LD"))191 config.substitutions.append(("%MD", "-MD"))192 config.substitutions.append(("%MT", "-MT"))193 config.substitutions.append(("%Gw", "-Gw"))194 config.substitutions.append(("%Oy-", "-Oy-"))195 196 base_lib = os.path.join(197 config.compiler_rt_libdir, "clang_rt.asan%%s%s.lib" % config.target_suffix198 )199 config.substitutions.append(("%asan_lib", base_lib % "_dynamic"))200 if config.asan_dynamic:201 config.substitutions.append(202 ("%asan_thunk", base_lib % "_dynamic_runtime_thunk")203 )204 else:205 config.substitutions.append(206 ("%asan_thunk", base_lib % "_static_runtime_thunk")207 )208 config.substitutions.append(("%asan_cxx_lib", base_lib % "_cxx"))209 config.substitutions.append(210 ("%asan_dynamic_runtime_thunk", base_lib % "_dynamic_runtime_thunk")211 )212 config.substitutions.append(213 ("%asan_static_runtime_thunk", base_lib % "_static_runtime_thunk")214 )215 config.substitutions.append(("%asan_dll_thunk", base_lib % "_dll_thunk"))216 else:217 # To make some of these tests work on MinGW target without changing their218 # behaviour for MSVC target, substitute clang-cl flags with gcc-like ones.219 config.substitutions.append(("%clang_cl ", build_invocation(target_cxxflags)))220 config.substitutions.append(221 ("%clang_cl_asan ", build_invocation(clang_asan_cxxflags))222 )223 config.substitutions.append(224 ("%clang_cl_nocxx_asan ", build_invocation(clang_asan_cflags))225 )226 config.substitutions.append(("%Od", "-O0"))227 config.substitutions.append(("%Fe", "-o"))228 config.substitutions.append(("%LD", "-shared"))229 config.substitutions.append(("%MD", ""))230 config.substitutions.append(("%MT", ""))231 config.substitutions.append(("%Gw", "-fdata-sections"))232 config.substitutions.append(("%Oy-", "-fno-omit-frame-pointer"))233 234# FIXME: De-hardcode this path.235asan_source_dir = os.path.join(236 get_required_attr(config, "compiler_rt_src_root"), "lib", "asan"237)238python_exec = shlex.quote(get_required_attr(config, "python_executable"))239# Setup path to asan_symbolize.py script.240asan_symbolize = os.path.join(asan_source_dir, "scripts", "asan_symbolize.py")241if not os.path.exists(asan_symbolize):242 lit_config.fatal("Can't find script on path %r" % asan_symbolize)243config.substitutions.append(244 ("%asan_symbolize", python_exec + " " + asan_symbolize + " ")245)246# Setup path to sancov.py script.247sanitizer_common_source_dir = os.path.join(248 get_required_attr(config, "compiler_rt_src_root"), "lib", "sanitizer_common"249)250sancov = os.path.join(sanitizer_common_source_dir, "scripts", "sancov.py")251if not os.path.exists(sancov):252 lit_config.fatal("Can't find script on path %r" % sancov)253config.substitutions.append(("%sancov ", python_exec + " " + sancov + " "))254 255# Determine kernel bitness256if config.host_arch.find("64") != -1 and not config.android:257 kernel_bits = "64"258else:259 kernel_bits = "32"260 261config.substitutions.append(262 ("CHECK-%kernel_bits", ("CHECK-kernel-" + kernel_bits + "-bits"))263)264 265config.substitutions.append(("%libdl", libdl_flag))266 267config.available_features.add("asan-" + config.bits + "-bits")268 269# Fast unwinder doesn't work with Thumb270if not config.arm_thumb:271 config.available_features.add("fast-unwinder-works")272 273# Turn on leak detection on 64-bit Linux.274leak_detection_android = (275 config.android276 and "android-thread-properties-api" in config.available_features277 and (config.target_arch in ["x86_64", "i386", "i686", "aarch64"])278)279leak_detection_linux = (280 (config.target_os == "Linux")281 and (not config.android)282 and (config.target_arch in ["x86_64", "i386", "riscv64", "loongarch64"])283)284leak_detection_mac = (285 (config.target_os == "Darwin")286 and (config.apple_platform == "osx")287 and (config.target_arch == "x86_64")288)289leak_detection_netbsd = (config.target_os == "NetBSD") and (290 config.target_arch in ["x86_64", "i386"]291)292if (293 leak_detection_android294 or leak_detection_linux295 or leak_detection_mac296 or leak_detection_netbsd297):298 config.available_features.add("leak-detection")299 300# Add the RT libdir to PATH directly so that we can successfully run the gtest301# binary to list its tests.302if config.target_os == "Windows":303 os.environ["PATH"] = os.path.pathsep.join(304 [config.compiler_rt_libdir, os.environ.get("PATH", "")]305 )306 307# msvc needs to be instructed where the compiler-rt libraries are308if config.compiler_id == "MSVC":309 config.environment["LIB"] = os.path.pathsep.join(310 [config.compiler_rt_libdir, config.environment.get("LIB", "")]311 )312 313# Default test suffixes.314config.suffixes = [".c", ".cpp"]315 316if config.target_os == "Darwin":317 config.suffixes.append(".mm")318 319if config.target_os == "Windows":320 config.substitutions.append(("%fPIC", ""))321 config.substitutions.append(("%fPIE", ""))322 config.substitutions.append(("%pie", ""))323else:324 config.substitutions.append(("%fPIC", "-fPIC"))325 config.substitutions.append(("%fPIE", "-fPIE"))326 config.substitutions.append(("%pie", "-pie"))327 328# Only run the tests on supported OSs.329if config.target_os not in ["Linux", "Darwin", "FreeBSD", "SunOS", "Windows", "NetBSD"]:330 config.unsupported = True331 332if not config.parallelism_group:333 config.parallelism_group = "shadow-memory"334 335if config.target_os == "NetBSD":336 config.substitutions.insert(0, ("%run", config.netbsd_noaslr_prefix))337