1"""
2Test that ASan memory history provider returns correct stack traces
3"""
4
5
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbplatform
11from lldbsuite.test import lldbutil
12
13
14class AsanTestCase(TestBase):
15
16    mydir = TestBase.compute_mydir(__file__)
17
18    @expectedFailureAll(
19        oslist=["linux"],
20        bugnumber="non-core functionality, need to reenable and fix later (DES 2014.11.07)")
21    @skipIfFreeBSD  # llvm.org/pr21136 runtimes not yet available by default
22    @expectedFailureNetBSD
23    @skipUnlessAddressSanitizer
24    def test(self):
25        self.build()
26        self.asan_tests()
27
28    def setUp(self):
29        # Call super's setUp().
30        TestBase.setUp(self)
31        self.line_malloc = line_number('main.c', '// malloc line')
32        self.line_malloc2 = line_number('main.c', '// malloc2 line')
33        self.line_free = line_number('main.c', '// free line')
34        self.line_breakpoint = line_number('main.c', '// break line')
35
36    def asan_tests(self):
37        exe = self.getBuildArtifact("a.out")
38        target = self.dbg.CreateTarget(exe)
39        self.assertTrue(target, VALID_TARGET)
40
41        self.registerSanitizerLibrariesWithTarget(target)
42
43        self.runCmd("breakpoint set -f main.c -l %d" % self.line_breakpoint)
44
45        # "memory history" command should not work without a process
46        self.expect("memory history 0",
47                    error=True,
48                    substrs=["invalid process"])
49
50        self.runCmd("run")
51
52        stop_reason = self.dbg.GetSelectedTarget().process.GetSelectedThread().GetStopReason()
53        if stop_reason == lldb.eStopReasonExec:
54            # On OS X 10.10 and older, we need to re-exec to enable
55            # interceptors.
56            self.runCmd("continue")
57
58        # the stop reason of the thread should be breakpoint.
59        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
60                    substrs=['stopped', 'stop reason = breakpoint'])
61
62        # test that the ASan dylib is present
63        self.expect(
64            "image lookup -n __asan_describe_address",
65            "__asan_describe_address should be present",
66            substrs=['1 match found'])
67
68        # test the 'memory history' command
69        self.expect(
70            "memory history 'pointer'",
71            substrs=[
72                'Memory deallocated by Thread',
73                'a.out`f2',
74                'main.c:%d' % self.line_free,
75                'Memory allocated by Thread',
76                'a.out`f1',
77                'main.c:%d' % self.line_malloc,
78            ])
79
80        # do the same using SB API
81        process = self.dbg.GetSelectedTarget().process
82        val = process.GetSelectedThread().GetSelectedFrame().EvaluateExpression("pointer")
83        addr = val.GetValueAsUnsigned()
84        threads = process.GetHistoryThreads(addr)
85        self.assertEqual(threads.GetSize(), 2)
86
87        history_thread = threads.GetThreadAtIndex(0)
88        self.assertTrue(history_thread.num_frames >= 2)
89        self.assertEqual(history_thread.frames[1].GetLineEntry(
90        ).GetFileSpec().GetFilename(), "main.c")
91        self.assertEqual(
92            history_thread.frames[1].GetLineEntry().GetLine(),
93            self.line_free)
94
95        history_thread = threads.GetThreadAtIndex(1)
96        self.assertTrue(history_thread.num_frames >= 2)
97        self.assertEqual(history_thread.frames[1].GetLineEntry(
98        ).GetFileSpec().GetFilename(), "main.c")
99        self.assertEqual(
100            history_thread.frames[1].GetLineEntry().GetLine(),
101            self.line_malloc)
102
103        # let's free the container (SBThreadCollection) and see if the
104        # SBThreads still live
105        threads = None
106        self.assertTrue(history_thread.num_frames >= 2)
107        self.assertEqual(history_thread.frames[1].GetLineEntry(
108        ).GetFileSpec().GetFilename(), "main.c")
109        self.assertEqual(
110            history_thread.frames[1].GetLineEntry().GetLine(),
111            self.line_malloc)
112
113        # ASan will break when a report occurs and we'll try the API then
114        self.runCmd("continue")
115
116        self.expect(
117            "thread list",
118            "Process should be stopped due to ASan report",
119            substrs=[
120                'stopped',
121                'stop reason = Use of deallocated memory'])
122
123        # make sure the 'memory history' command still works even when we're
124        # generating a report now
125        self.expect(
126            "memory history 'another_pointer'",
127            substrs=[
128                'Memory allocated by Thread',
129                'a.out`f1',
130                'main.c:%d' %
131                self.line_malloc2])
132