Home | History | Annotate | Download | only in asan
      1 # -*- Python -*-
      2 
      3 import os
      4 import platform
      5 
      6 import lit.formats
      7 
      8 def get_required_attr(config, attr_name):
      9   attr_value = getattr(config, attr_name, None)
     10   if attr_value == None:
     11     lit_config.fatal(
     12       "No attribute %r in test configuration! You may need to run "
     13       "tests from your build directory or add this attribute "
     14       "to lit.site.cfg " % attr_name)
     15   return attr_value
     16 
     17 def push_dynamic_library_lookup_path(config, new_path):
     18   if platform.system() == 'Windows':
     19     dynamic_library_lookup_var = 'PATH'
     20   elif platform.system() == 'Darwin':
     21     dynamic_library_lookup_var = 'DYLD_LIBRARY_PATH'
     22   else:
     23     dynamic_library_lookup_var = 'LD_LIBRARY_PATH'
     24 
     25   new_ld_library_path = os.path.pathsep.join(
     26     (new_path, config.environment.get(dynamic_library_lookup_var, '')))
     27   config.environment[dynamic_library_lookup_var] = new_ld_library_path
     28 
     29 # Setup config name.
     30 config.name = 'AddressSanitizer' + config.name_suffix
     31 
     32 # Platform-specific default ASAN_OPTIONS for lit tests.
     33 default_asan_opts = ''
     34 if config.host_os == 'Darwin':
     35   # On Darwin, we default to `abort_on_error=1`, which would make tests run
     36   # much slower. Let's override this and run lit tests with 'abort_on_error=0'.
     37   # Also, make sure we do not overwhelm the syslog while testing.
     38   default_asan_opts = 'abort_on_error=0'
     39   default_asan_opts += ':log_to_syslog=0'
     40 if default_asan_opts:
     41   config.environment['ASAN_OPTIONS'] = default_asan_opts
     42   default_asan_opts += ':'
     43 config.substitutions.append(('%env_asan_opts=',
     44                              'env ASAN_OPTIONS=' + default_asan_opts))
     45 
     46 # Setup source root.
     47 config.test_source_root = os.path.dirname(__file__)
     48 
     49 # There is no libdl on FreeBSD.
     50 if config.host_os != 'FreeBSD':
     51   libdl_flag = "-ldl"
     52 else:
     53   libdl_flag = ""
     54 
     55 # GCC-ASan doesn't link in all the necessary libraries automatically, so
     56 # we have to do it ourselves.
     57 if config.compiler_id == 'GNU':
     58   extra_linkflags = ["-pthread", "-lstdc++", libdl_flag]
     59 else:
     60   extra_linkflags = []
     61 
     62 # BFD linker in 64-bit android toolchains fails to find libm.so, which is a
     63 # transitive shared library dependency (via asan runtime).
     64 if config.android:
     65   extra_linkflags += ["-lm"]
     66 
     67 # Setup default compiler flags used with -fsanitize=address option.
     68 # FIXME: Review the set of required flags and check if it can be reduced.
     69 target_cflags = [get_required_attr(config, "target_cflags")] + extra_linkflags
     70 target_cxxflags = config.cxx_mode_flags + target_cflags
     71 clang_asan_static_cflags = (["-fsanitize=address",
     72                             "-mno-omit-leaf-frame-pointer",
     73                             "-fno-omit-frame-pointer",
     74                             "-fno-optimize-sibling-calls"] +
     75                             config.debug_info_flags + target_cflags)
     76 if config.target_arch == 's390x':
     77   clang_asan_static_cflags.append("-mbackchain")
     78 clang_asan_static_cxxflags = config.cxx_mode_flags + clang_asan_static_cflags
     79 
     80 if config.asan_dynamic:
     81   clang_asan_cflags = clang_asan_static_cflags + ['-shared-libasan']
     82   clang_asan_cxxflags = clang_asan_static_cxxflags + ['-shared-libasan']
     83   config.available_features.add("asan-dynamic-runtime")
     84 else:
     85   clang_asan_cflags = clang_asan_static_cflags
     86   clang_asan_cxxflags = clang_asan_static_cxxflags
     87   config.available_features.add("asan-static-runtime")
     88 
     89 asan_lit_source_dir = get_required_attr(config, "asan_lit_source_dir")
     90 if config.android == "1":
     91   config.available_features.add('android')
     92   clang_wrapper = os.path.join(asan_lit_source_dir,
     93                                "android_commands", "android_compile.py") + " "
     94 else:
     95   config.available_features.add('not-android')
     96   clang_wrapper = ""
     97 
     98 def build_invocation(compile_flags):
     99   return " " + " ".join([clang_wrapper, config.clang] + compile_flags) + " "
    100 
    101 config.substitutions.append( ("%clang ", build_invocation(target_cflags)) )
    102 config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) )
    103 config.substitutions.append( ("%clang_asan ", build_invocation(clang_asan_cflags)) )
    104 config.substitutions.append( ("%clangxx_asan ", build_invocation(clang_asan_cxxflags)) )
    105 config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % config.target_arch))
    106 if config.asan_dynamic:
    107   config.substitutions.append( ("%clang_asan_static ", build_invocation(clang_asan_static_cflags)) )
    108   config.substitutions.append( ("%clangxx_asan_static ", build_invocation(clang_asan_static_cxxflags)) )
    109 
    110 # Windows-specific tests might also use the clang-cl.exe driver.
    111 if platform.system() == 'Windows':
    112   clang_cl_asan_cxxflags = ["-fsanitize=address",
    113                             "-Wno-deprecated-declarations",
    114                             "-WX",
    115                             "-D_HAS_EXCEPTIONS=0",
    116                             "-Zi"] + target_cflags
    117   if config.asan_dynamic:
    118     clang_cl_asan_cxxflags.append("-MD")
    119   clang_invocation = build_invocation(clang_cl_asan_cxxflags)
    120   clang_cl_invocation = clang_invocation.replace("clang.exe","clang-cl.exe")
    121   config.substitutions.append( ("%clang_cl_asan ", clang_cl_invocation) )
    122   base_lib = os.path.join(config.compiler_rt_libdir, "clang_rt.asan%%s-%s.lib" % config.target_arch)
    123   config.substitutions.append( ("%asan_lib", base_lib % "") )
    124   config.substitutions.append( ("%asan_cxx_lib", base_lib % "_cxx") )
    125   config.substitutions.append( ("%asan_dll_thunk", base_lib % "_dll_thunk") )
    126 
    127 # FIXME: De-hardcode this path.
    128 asan_source_dir = os.path.join(
    129   get_required_attr(config, "compiler_rt_src_root"), "lib", "asan")
    130 # Setup path to asan_symbolize.py script.
    131 asan_symbolize = os.path.join(asan_source_dir, "scripts", "asan_symbolize.py")
    132 if not os.path.exists(asan_symbolize):
    133   lit_config.fatal("Can't find script on path %r" % asan_symbolize)
    134 python_exec = get_required_attr(config, "python_executable")
    135 config.substitutions.append( ("%asan_symbolize", python_exec + " " + asan_symbolize + " ") )
    136 # Setup path to sancov.py script.
    137 sanitizer_common_source_dir = os.path.join(
    138   get_required_attr(config, "compiler_rt_src_root"), "lib", "sanitizer_common")
    139 sancov = os.path.join(sanitizer_common_source_dir, "scripts", "sancov.py")
    140 if not os.path.exists(sancov):
    141   lit_config.fatal("Can't find script on path %r" % sancov)
    142 python_exec = get_required_attr(config, "python_executable")
    143 config.substitutions.append( ("%sancov ", python_exec + " " + sancov + " ") )
    144 
    145 # Determine kernel bitness
    146 if config.host_arch.find('64') != -1 and config.android != "1":
    147   kernel_bits = '64'
    148 else:
    149   kernel_bits = '32'
    150 
    151 config.substitutions.append( ('CHECK-%kernel_bits', ("CHECK-kernel-" + kernel_bits + "-bits")))
    152 
    153 config.substitutions.append( ("%libdl", libdl_flag) )
    154 
    155 config.available_features.add("asan-" + config.bits + "-bits")
    156 
    157 if config.host_os == 'Darwin':
    158   config.substitutions.append( ("%ld_flags_rpath_exe", '-Wl,-rpath,@executable_path/ %dynamiclib') )
    159   config.substitutions.append( ("%ld_flags_rpath_so", '-install_name @rpath/`basename %dynamiclib`') )
    160 elif config.host_os == 'FreeBSD':
    161   config.substitutions.append( ("%ld_flags_rpath_exe", "-Wl,-z,origin -Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec") )
    162   config.substitutions.append( ("%ld_flags_rpath_so", '') )
    163 elif config.host_os == 'Linux':
    164   config.substitutions.append( ("%ld_flags_rpath_exe", "-Wl,-rpath,\$ORIGIN -L%T -l%xdynamiclib_namespec") )
    165   config.substitutions.append( ("%ld_flags_rpath_so", '') )
    166 
    167 # Must be defined after the substitutions that use %dynamiclib.
    168 config.substitutions.append( ("%dynamiclib", '%T/lib%xdynamiclib_namespec.so') )
    169 config.substitutions.append( ("%xdynamiclib_namespec", '$(basename %t).dynamic') )
    170 
    171 # Allow tests to use REQUIRES=stable-runtime.  For use when you cannot use XFAIL
    172 # because the test hangs. Adding armhf as we now have two modes.
    173 if config.target_arch != 'arm' and config.target_arch != 'armhf' and config.target_arch != 'aarch64':
    174   config.available_features.add('stable-runtime')
    175 
    176 # Turn on leak detection on 64-bit Linux.
    177 if config.host_os == 'Linux' and config.target_arch == 'x86_64':
    178   config.available_features.add('leak-detection')
    179 
    180 # Set LD_LIBRARY_PATH to pick dynamic runtime up properly.
    181 push_dynamic_library_lookup_path(config, config.compiler_rt_libdir)
    182 
    183 # GCC-ASan uses dynamic runtime by default.
    184 if config.compiler_id == 'GNU':
    185   gcc_dir = os.path.dirname(config.clang)
    186   libasan_dir = os.path.join(gcc_dir, "..", "lib" + config.bits)
    187   push_dynamic_library_lookup_path(config, libasan_dir)
    188 
    189 # Default test suffixes.
    190 config.suffixes = ['.c', '.cc', '.cpp']
    191 
    192 if config.host_os == 'Darwin':
    193   config.suffixes.append('.mm')
    194 
    195 # Only run the tests on supported OSs.
    196 if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows']:
    197   config.unsupported = True
    198