199451b44SJordan Rupprecht""" 299451b44SJordan RupprechtTests basic ThreadSanitizer support (detecting a data race). 399451b44SJordan Rupprecht""" 499451b44SJordan Rupprecht 599451b44SJordan Rupprechtimport lldb 699451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 799451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 899451b44SJordan Rupprechtimport lldbsuite.test.lldbutil as lldbutil 999451b44SJordan Rupprechtimport json 1099451b44SJordan Rupprecht 1199451b44SJordan Rupprecht 1299451b44SJordan Rupprechtclass TsanBasicTestCase(TestBase): 1399451b44SJordan Rupprecht 1499451b44SJordan Rupprecht @expectedFailureAll( 1599451b44SJordan Rupprecht oslist=["linux"], 1699451b44SJordan Rupprecht bugnumber="non-core functionality, need to reenable and fix later (DES 2014.11.07)") 1799451b44SJordan Rupprecht @expectedFailureNetBSD 1899451b44SJordan Rupprecht @skipIfFreeBSD # llvm.org/pr21136 runtimes not yet available by default 1999451b44SJordan Rupprecht @skipIfRemote 2099451b44SJordan Rupprecht @skipUnlessThreadSanitizer 21*5f2e8f57SJonas Devlieghere @no_debug_info_test 2299451b44SJordan Rupprecht def test(self): 2399451b44SJordan Rupprecht self.build() 2499451b44SJordan Rupprecht self.tsan_tests() 2599451b44SJordan Rupprecht 2699451b44SJordan Rupprecht def setUp(self): 2799451b44SJordan Rupprecht # Call super's setUp(). 2899451b44SJordan Rupprecht TestBase.setUp(self) 2999451b44SJordan Rupprecht self.line_malloc = line_number('main.c', '// malloc line') 3099451b44SJordan Rupprecht self.line_thread1 = line_number('main.c', '// thread1 line') 3199451b44SJordan Rupprecht self.line_thread2 = line_number('main.c', '// thread2 line') 3299451b44SJordan Rupprecht 3399451b44SJordan Rupprecht def tsan_tests(self): 3499451b44SJordan Rupprecht exe = self.getBuildArtifact("a.out") 3599451b44SJordan Rupprecht self.expect( 3699451b44SJordan Rupprecht "file " + exe, 3799451b44SJordan Rupprecht patterns=["Current executable set to .*a.out"]) 3899451b44SJordan Rupprecht 3999451b44SJordan Rupprecht self.runCmd("run") 4099451b44SJordan Rupprecht 4199451b44SJordan Rupprecht stop_reason = self.dbg.GetSelectedTarget().process.GetSelectedThread().GetStopReason() 4299451b44SJordan Rupprecht if stop_reason == lldb.eStopReasonExec: 4399451b44SJordan Rupprecht # On OS X 10.10 and older, we need to re-exec to enable 4499451b44SJordan Rupprecht # interceptors. 4599451b44SJordan Rupprecht self.runCmd("continue") 4699451b44SJordan Rupprecht 4799451b44SJordan Rupprecht # the stop reason of the thread should be breakpoint. 4899451b44SJordan Rupprecht self.expect("thread list", "A data race should be detected", 4999451b44SJordan Rupprecht substrs=['stopped', 'stop reason = Data race detected']) 5099451b44SJordan Rupprecht 5199451b44SJordan Rupprecht self.assertEqual( 5299451b44SJordan Rupprecht self.dbg.GetSelectedTarget().process.GetSelectedThread().GetStopReason(), 5399451b44SJordan Rupprecht lldb.eStopReasonInstrumentation) 5499451b44SJordan Rupprecht 5599451b44SJordan Rupprecht # test that the TSan dylib is present 5699451b44SJordan Rupprecht self.expect( 5799451b44SJordan Rupprecht "image lookup -n __tsan_get_current_report", 5899451b44SJordan Rupprecht "__tsan_get_current_report should be present", 5999451b44SJordan Rupprecht substrs=['1 match found']) 6099451b44SJordan Rupprecht 6199451b44SJordan Rupprecht # We should be stopped in __tsan_on_report 6299451b44SJordan Rupprecht process = self.dbg.GetSelectedTarget().process 6399451b44SJordan Rupprecht thread = process.GetSelectedThread() 6499451b44SJordan Rupprecht frame = thread.GetSelectedFrame() 653cc37622SDave Lee self.assertIn("__tsan_on_report", frame.GetFunctionName()) 6699451b44SJordan Rupprecht 6799451b44SJordan Rupprecht # The stopped thread backtrace should contain either line1 or line2 6899451b44SJordan Rupprecht # from main.c. 6999451b44SJordan Rupprecht found = False 7099451b44SJordan Rupprecht for i in range(0, thread.GetNumFrames()): 7199451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(i) 7299451b44SJordan Rupprecht if frame.GetLineEntry().GetFileSpec().GetFilename() == "main.c": 7399451b44SJordan Rupprecht if frame.GetLineEntry().GetLine() == self.line_thread1: 7499451b44SJordan Rupprecht found = True 7599451b44SJordan Rupprecht if frame.GetLineEntry().GetLine() == self.line_thread2: 7699451b44SJordan Rupprecht found = True 7799451b44SJordan Rupprecht self.assertTrue(found) 7899451b44SJordan Rupprecht 7999451b44SJordan Rupprecht self.expect( 8099451b44SJordan Rupprecht "thread info -s", 8199451b44SJordan Rupprecht "The extended stop info should contain the TSan provided fields", 8299451b44SJordan Rupprecht substrs=[ 8399451b44SJordan Rupprecht "instrumentation_class", 8499451b44SJordan Rupprecht "description", 8599451b44SJordan Rupprecht "mops"]) 8699451b44SJordan Rupprecht 8799451b44SJordan Rupprecht output_lines = self.res.GetOutput().split('\n') 8899451b44SJordan Rupprecht json_line = '\n'.join(output_lines[2:]) 8999451b44SJordan Rupprecht data = json.loads(json_line) 9099451b44SJordan Rupprecht self.assertEqual(data["instrumentation_class"], "ThreadSanitizer") 9199451b44SJordan Rupprecht self.assertEqual(data["issue_type"], "data-race") 9299451b44SJordan Rupprecht self.assertEqual(len(data["mops"]), 2) 9399451b44SJordan Rupprecht 9499451b44SJordan Rupprecht backtraces = thread.GetStopReasonExtendedBacktraces( 9599451b44SJordan Rupprecht lldb.eInstrumentationRuntimeTypeAddressSanitizer) 9699451b44SJordan Rupprecht self.assertEqual(backtraces.GetSize(), 0) 9799451b44SJordan Rupprecht 9899451b44SJordan Rupprecht backtraces = thread.GetStopReasonExtendedBacktraces( 9999451b44SJordan Rupprecht lldb.eInstrumentationRuntimeTypeThreadSanitizer) 10099451b44SJordan Rupprecht self.assertTrue(backtraces.GetSize() >= 2) 10199451b44SJordan Rupprecht 10299451b44SJordan Rupprecht # First backtrace is a memory operation 10399451b44SJordan Rupprecht thread = backtraces.GetThreadAtIndex(0) 10499451b44SJordan Rupprecht found = False 10599451b44SJordan Rupprecht for i in range(0, thread.GetNumFrames()): 10699451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(i) 10799451b44SJordan Rupprecht if frame.GetLineEntry().GetFileSpec().GetFilename() == "main.c": 10899451b44SJordan Rupprecht if frame.GetLineEntry().GetLine() == self.line_thread1: 10999451b44SJordan Rupprecht found = True 11099451b44SJordan Rupprecht if frame.GetLineEntry().GetLine() == self.line_thread2: 11199451b44SJordan Rupprecht found = True 11299451b44SJordan Rupprecht self.assertTrue(found) 11399451b44SJordan Rupprecht 11499451b44SJordan Rupprecht # Second backtrace is a memory operation 11599451b44SJordan Rupprecht thread = backtraces.GetThreadAtIndex(1) 11699451b44SJordan Rupprecht found = False 11799451b44SJordan Rupprecht for i in range(0, thread.GetNumFrames()): 11899451b44SJordan Rupprecht frame = thread.GetFrameAtIndex(i) 11999451b44SJordan Rupprecht if frame.GetLineEntry().GetFileSpec().GetFilename() == "main.c": 12099451b44SJordan Rupprecht if frame.GetLineEntry().GetLine() == self.line_thread1: 12199451b44SJordan Rupprecht found = True 12299451b44SJordan Rupprecht if frame.GetLineEntry().GetLine() == self.line_thread2: 12399451b44SJordan Rupprecht found = True 12499451b44SJordan Rupprecht self.assertTrue(found) 12599451b44SJordan Rupprecht 12699451b44SJordan Rupprecht self.runCmd("continue") 12799451b44SJordan Rupprecht 12899451b44SJordan Rupprecht # the stop reason of the thread should be a SIGABRT. 12999451b44SJordan Rupprecht self.expect("thread list", "We should be stopped due a SIGABRT", 13099451b44SJordan Rupprecht substrs=['stopped', 'stop reason = signal SIGABRT']) 13199451b44SJordan Rupprecht 13299451b44SJordan Rupprecht # test that we're in pthread_kill now (TSan abort the process) 13399451b44SJordan Rupprecht self.expect("thread list", "We should be stopped in pthread_kill", 13499451b44SJordan Rupprecht substrs=['pthread_kill']) 135