1"""
2Tests that TSan and LLDB have correct thread numbers.
3"""
4
5import lldb
6from lldbsuite.test.lldbtest import *
7from lldbsuite.test.decorators import *
8import lldbsuite.test.lldbutil as lldbutil
9import json
10
11
12class TsanThreadNumbersTestCase(TestBase):
13
14    mydir = TestBase.compute_mydir(__file__)
15
16    @expectedFailureAll(
17        oslist=["linux"],
18        bugnumber="non-core functionality, need to reenable and fix later (DES 2014.11.07)")
19    @expectedFailureNetBSD
20    @skipIfFreeBSD  # llvm.org/pr21136 runtimes not yet available by default
21    @skipIfRemote
22    @skipUnlessThreadSanitizer
23    def test(self):
24        self.build()
25        self.tsan_tests()
26
27    def tsan_tests(self):
28        exe = self.getBuildArtifact("a.out")
29        self.expect(
30            "file " + exe,
31            patterns=["Current executable set to .*a.out"])
32
33        self.runCmd("run")
34
35        stop_reason = self.dbg.GetSelectedTarget().process.GetSelectedThread().GetStopReason()
36        if stop_reason == lldb.eStopReasonExec:
37            # On OS X 10.10 and older, we need to re-exec to enable
38            # interceptors.
39            self.runCmd("continue")
40
41        # the stop reason of the thread should be breakpoint.
42        self.expect("thread list", "A data race should be detected",
43                    substrs=['stopped', 'stop reason = Data race detected'])
44
45        self.assertEqual(
46            self.dbg.GetSelectedTarget().process.GetSelectedThread().GetStopReason(),
47            lldb.eStopReasonInstrumentation)
48
49        report_thread_id = self.dbg.GetSelectedTarget(
50        ).process.GetSelectedThread().GetIndexID()
51
52        self.expect(
53            "thread info -s",
54            "The extended stop info should contain the TSan provided fields",
55            substrs=[
56                "instrumentation_class",
57                "description",
58                "mops"])
59
60        output_lines = self.res.GetOutput().split('\n')
61        json_line = '\n'.join(output_lines[2:])
62        data = json.loads(json_line)
63        self.assertEqual(data["instrumentation_class"], "ThreadSanitizer")
64        self.assertEqual(data["issue_type"], "data-race")
65        self.assertEqual(len(data["mops"]), 2)
66
67        self.assertEqual(data["mops"][0]["thread_id"], report_thread_id)
68
69        other_thread_id = data["mops"][1]["thread_id"]
70        self.assertNotEqual(other_thread_id, report_thread_id)
71        other_thread = self.dbg.GetSelectedTarget(
72        ).process.GetThreadByIndexID(other_thread_id)
73        self.assertTrue(other_thread.IsValid())
74
75        self.runCmd("thread select %d" % other_thread_id)
76
77        self.expect(
78            "thread backtrace",
79            "The other thread should be stopped in f1 or f2",
80            substrs=[
81                "a.out",
82                "main.c"])
83