Index: test/functionalities/asan/Makefile =================================================================== --- test/functionalities/asan/Makefile +++ test/functionalities/asan/Makefile @@ -1,6 +1,5 @@ LEVEL = ../../make C_SOURCES := main.c -CFLAGS := $(CFLAGS) -fsanitize=address -g include $(LEVEL)/Makefile.rules Index: test/functionalities/asan/TestMemoryHistory.py =================================================================== --- test/functionalities/asan/TestMemoryHistory.py +++ test/functionalities/asan/TestMemoryHistory.py @@ -12,24 +12,19 @@ mydir = TestBase.compute_mydir(__file__) - # The default compiler ("clang") may not support Address Sanitizer or it - # may not have the debugging API which was recently added, so we're calling - # self.useBuiltClang() to use clang from the llvm-build directory instead - @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") @skipIfRemote + @skipIfAddressSanitizerUnsupported @dsym_test def test_with_dsym (self): - compiler = self.findBuiltClang () - self.buildDsym (None, compiler) + self.buildDsym (None, None, {"CFLAGS": "-fsanitize=address -g"}) self.asan_tests () - @skipIfFreeBSD # llvm.org/pr21136 runtimes not yet available by default @skipIfRemote + @skipIfAddressSanitizerUnsupported @dwarf_test def test_with_dwarf (self): - compiler = self.findBuiltClang () - self.buildDwarf (None, compiler) + self.buildDwarf (None, None, {"CFLAGS": "-fsanitize=address -g"}) self.asan_tests () def setUp(self): @@ -53,12 +48,15 @@ self.runCmd("run") - # ASan will relaunch the process to insert its library. - self.expect("thread list", "Process should be stopped due to exec.", - substrs = ['stopped', 'stop reason = exec']) + process = self.dbg.GetSelectedTarget().process + thread = process.GetSelectedThread() + stop_reason = thread.GetStopReason() + if stop_reason == lldb.eStopReasonExec: + # On OS X, ASan will relaunch the process to insert its library. + self.expect("thread list", "Process should be stopped due to exec.", + substrs = ['stopped', 'stop reason = exec']) + self.runCmd("continue") - self.runCmd("continue") - # the stop reason of the thread should be breakpoint. self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, substrs = ['stopped', 'stop reason = breakpoint']) @@ -74,7 +72,6 @@ 'Memory deallocated at', 'a.out`f2', 'main.c:%d' % self.line_free]) # do the same using SB API - process = self.dbg.GetSelectedTarget().process val = process.GetSelectedThread().GetSelectedFrame().EvaluateExpression("pointer") addr = val.GetValueAsUnsigned() threads = process.GetHistoryThreads(addr); Index: test/functionalities/asan/TestReportData.py =================================================================== --- test/functionalities/asan/TestReportData.py +++ test/functionalities/asan/TestReportData.py @@ -13,24 +13,19 @@ mydir = TestBase.compute_mydir(__file__) - # The default compiler ("clang") may not support Address Sanitizer or it - # may not have the debugging API which was recently added, so we're calling - # self.useBuiltClang() to use clang from the llvm-build directory instead - @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") @skipIfRemote + @skipIfAddressSanitizerUnsupported @dsym_test def test_with_dsym (self): - compiler = self.findBuiltClang () - self.buildDsym (None, compiler) + self.buildDsym (None, None, {"CFLAGS": "-fsanitize=address -g"}) self.asan_tests () - @skipIfFreeBSD # llvm.org/pr21136 runtimes not yet available by default @skipIfRemote + @skipIfAddressSanitizerUnsupported @dwarf_test def test_with_dwarf (self): - compiler = self.findBuiltClang () - self.buildDwarf (None, compiler) + self.buildDwarf (None, None, {"CFLAGS": "-fsanitize=address -g"}) self.asan_tests () def setUp(self): @@ -45,12 +40,24 @@ def asan_tests (self): exe = os.path.join (os.getcwd(), "a.out") self.expect("file " + exe, patterns = [ "Current executable set to .*a.out" ]) + + self.runCmd("breakpoint set -f main.c -l %d" % self.line_breakpoint) + self.runCmd("run") - # ASan will relaunch the process to insert its library. - self.expect("thread list", "Process should be stopped due to exec.", - substrs = ['stopped', 'stop reason = exec']) + process = self.dbg.GetSelectedTarget().process + thread = process.GetSelectedThread() + stop_reason = thread.GetStopReason() + if stop_reason == lldb.eStopReasonExec: + # On OS X, ASan will relaunch the process to insert its library. + self.expect("thread list", "Process should be stopped due to exec.", + substrs = ['stopped', 'stop reason = exec']) + self.runCmd("continue") + # the stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', 'stop reason = breakpoint']) + # no extended info when we have no ASan report thread = self.dbg.GetSelectedTarget().process.GetSelectedThread() s = lldb.SBStream() Index: test/lldbtest.py =================================================================== --- test/lldbtest.py +++ test/lldbtest.py @@ -499,6 +499,17 @@ def expectedFailureLinux(bugnumber=None, compilers=None): if bugnumber: return expectedFailureOS('linux', bugnumber, compilers) +def skipIf(skip_fn, method, reason): + def skipIf_impl(func): + @wraps(func) + def wrapper(self, *args, **kwargs): + if skip_fn(self): + self.skipTest(reason) + else: + return func(self, *args, **kwargs) + return wrapper + return skipIf_impl(method) + def skipIfRemote(func): """Decorate the item to skip tests if testing remotely.""" if isinstance(func, type) and issubclass(func, unittest2.TestCase): @@ -669,6 +680,14 @@ func(*args, **kwargs) return wrapper +def skipIfAddressSanitizerUnsupported(method): + """ + Decorate the item to skip tests that should skipped when the compiler we're using doesn't + support compiling with AddressSanitizer. + """ + def fn(self): + return not self.compilerSupportsAddressSanitizer() + return skipIf(fn, method, "skipping because compiler doesn't support AddressSanitizer") class Base(unittest2.TestCase): """ @@ -864,6 +883,8 @@ # See HideStdout(self). self.sys_stdout_hidden = False + self.cachedCompilerSupportsAddressSanitizer = None + # set environment variable names for finding shared libraries if sys.platform.startswith("darwin"): self.dylibPath = 'DYLD_LIBRARY_PATH' @@ -1363,22 +1384,6 @@ if not module.buildDwarf(self, architecture, compiler, dictionary, clean): raise Exception("Don't know how to build binary with dwarf") - def findBuiltClang(self): - """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler).""" - paths_to_try = [ - "llvm-build/Release+Asserts/x86_64/Release+Asserts/bin/clang", - "llvm-build/Debug+Asserts/x86_64/Debug+Asserts/bin/clang", - "llvm-build/Release/x86_64/Release/bin/clang", - "llvm-build/Debug/x86_64/Debug/bin/clang", - ] - lldb_root_path = os.path.join(os.path.dirname(__file__), "..") - for p in paths_to_try: - path = os.path.join(lldb_root_path, p) - if os.path.exists(path): - return path - - return os.environ["CC"] - def getBuildFlags(self, use_cpp11=True, use_libcxx=False, use_libstdcxx=False, use_pthreads=True): """ Returns a dictionary (which can be provided to build* functions above) which contains OS-specific build flags. @@ -1443,6 +1448,41 @@ else: return ['libc++.1.dylib','libc++abi.dylib'] + def compilerSupportsAddressSanitizer(self): + if self.cachedCompilerSupportsAddressSanitizer != None: + return self.cachedCompilerSupportsAddressSanitizer + + self.cachedCompilerSupportsAddressSanitizer = False + + # We only support clang's AddressSanitizer. + if not "clang" in self.getCompiler(): + return False + + # Older versions of clang don't have the debugging functions in ASan. + if self.expectedCompilerVersion(["<", "3.6.0"]): + return False + + # Save old working directory. + oldcwd = os.getcwd() + + os.chdir(os.path.dirname(__file__) + "/functionalities/asan") + + # This should always work + self.buildDefault(); + + # This will fail if the compiler doesn't have AddressSanitizer + try: + self.buildDefault (None, None, {"CFLAGS": "-fsanitize=address"}) + self.cachedCompilerSupportsAddressSanitizer = True + except CalledProcessError: + pass + + # Clean up + self.cleanup(); + os.chdir(oldcwd) + + return self.cachedCompilerSupportsAddressSanitizer + class TestBase(Base): """ This abstract base class is meant to be subclassed. It provides default