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