199451b44SJordan Rupprecht"""
299451b44SJordan RupprechtTest that ASan memory history provider returns correct stack traces
399451b44SJordan Rupprecht"""
499451b44SJordan Rupprecht
599451b44SJordan Rupprecht
699451b44SJordan Rupprecht
799451b44SJordan Rupprechtimport lldb
899451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
999451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
1099451b44SJordan Rupprechtfrom lldbsuite.test import lldbplatform
1199451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
1299451b44SJordan Rupprecht
1399451b44SJordan Rupprecht
1499451b44SJordan Rupprechtclass AsanTestCase(TestBase):
1599451b44SJordan Rupprecht
1699451b44SJordan Rupprecht    @skipIfFreeBSD  # llvm.org/pr21136 runtimes not yet available by default
1799451b44SJordan Rupprecht    @expectedFailureNetBSD
1899451b44SJordan Rupprecht    @skipUnlessAddressSanitizer
1999451b44SJordan Rupprecht    def test(self):
2099451b44SJordan Rupprecht        self.build()
2199451b44SJordan Rupprecht        self.asan_tests()
2299451b44SJordan Rupprecht
2399451b44SJordan Rupprecht    def setUp(self):
2499451b44SJordan Rupprecht        # Call super's setUp().
2599451b44SJordan Rupprecht        TestBase.setUp(self)
2699451b44SJordan Rupprecht        self.line_malloc = line_number('main.c', '// malloc line')
2799451b44SJordan Rupprecht        self.line_malloc2 = line_number('main.c', '// malloc2 line')
2899451b44SJordan Rupprecht        self.line_free = line_number('main.c', '// free line')
2999451b44SJordan Rupprecht        self.line_breakpoint = line_number('main.c', '// break line')
3099451b44SJordan Rupprecht
3199451b44SJordan Rupprecht    def asan_tests(self):
3254c26872SRaphael Isemann        target = self.createTestTarget()
3399451b44SJordan Rupprecht
3499451b44SJordan Rupprecht        self.registerSanitizerLibrariesWithTarget(target)
3599451b44SJordan Rupprecht
3699451b44SJordan Rupprecht        self.runCmd("breakpoint set -f main.c -l %d" % self.line_breakpoint)
3799451b44SJordan Rupprecht
3899451b44SJordan Rupprecht        # "memory history" command should not work without a process
3999451b44SJordan Rupprecht        self.expect("memory history 0",
4099451b44SJordan Rupprecht                    error=True,
41*77bfdeb0SJonas Devlieghere                    substrs=["Command requires a current process"])
4299451b44SJordan Rupprecht
4399451b44SJordan Rupprecht        self.runCmd("run")
4499451b44SJordan Rupprecht
4599451b44SJordan Rupprecht        stop_reason = self.dbg.GetSelectedTarget().process.GetSelectedThread().GetStopReason()
4699451b44SJordan Rupprecht        if stop_reason == lldb.eStopReasonExec:
4799451b44SJordan Rupprecht            # On OS X 10.10 and older, we need to re-exec to enable
4899451b44SJordan Rupprecht            # interceptors.
4999451b44SJordan Rupprecht            self.runCmd("continue")
5099451b44SJordan Rupprecht
5199451b44SJordan Rupprecht        # the stop reason of the thread should be breakpoint.
5299451b44SJordan Rupprecht        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
5399451b44SJordan Rupprecht                    substrs=['stopped', 'stop reason = breakpoint'])
5499451b44SJordan Rupprecht
5599451b44SJordan Rupprecht        # test that the ASan dylib is present
5699451b44SJordan Rupprecht        self.expect(
5799451b44SJordan Rupprecht            "image lookup -n __asan_describe_address",
5899451b44SJordan Rupprecht            "__asan_describe_address should be present",
5999451b44SJordan Rupprecht            substrs=['1 match found'])
6099451b44SJordan Rupprecht
6199451b44SJordan Rupprecht        # test the 'memory history' command
6299451b44SJordan Rupprecht        self.expect(
6399451b44SJordan Rupprecht            "memory history 'pointer'",
6499451b44SJordan Rupprecht            substrs=[
6599451b44SJordan Rupprecht                'Memory deallocated by Thread',
6699451b44SJordan Rupprecht                'a.out`f2',
6799451b44SJordan Rupprecht                'main.c:%d' % self.line_free,
6899451b44SJordan Rupprecht                'Memory allocated by Thread',
6999451b44SJordan Rupprecht                'a.out`f1',
7099451b44SJordan Rupprecht                'main.c:%d' % self.line_malloc,
7199451b44SJordan Rupprecht            ])
7299451b44SJordan Rupprecht
7399451b44SJordan Rupprecht        # do the same using SB API
7499451b44SJordan Rupprecht        process = self.dbg.GetSelectedTarget().process
7599451b44SJordan Rupprecht        val = process.GetSelectedThread().GetSelectedFrame().EvaluateExpression("pointer")
7699451b44SJordan Rupprecht        addr = val.GetValueAsUnsigned()
7799451b44SJordan Rupprecht        threads = process.GetHistoryThreads(addr)
7899451b44SJordan Rupprecht        self.assertEqual(threads.GetSize(), 2)
7999451b44SJordan Rupprecht
8099451b44SJordan Rupprecht        history_thread = threads.GetThreadAtIndex(0)
8199451b44SJordan Rupprecht        self.assertTrue(history_thread.num_frames >= 2)
8299451b44SJordan Rupprecht        self.assertEqual(history_thread.frames[1].GetLineEntry(
8399451b44SJordan Rupprecht        ).GetFileSpec().GetFilename(), "main.c")
8499451b44SJordan Rupprecht        self.assertEqual(
8599451b44SJordan Rupprecht            history_thread.frames[1].GetLineEntry().GetLine(),
8699451b44SJordan Rupprecht            self.line_free)
8799451b44SJordan Rupprecht
8899451b44SJordan Rupprecht        history_thread = threads.GetThreadAtIndex(1)
8999451b44SJordan Rupprecht        self.assertTrue(history_thread.num_frames >= 2)
9099451b44SJordan Rupprecht        self.assertEqual(history_thread.frames[1].GetLineEntry(
9199451b44SJordan Rupprecht        ).GetFileSpec().GetFilename(), "main.c")
9299451b44SJordan Rupprecht        self.assertEqual(
9399451b44SJordan Rupprecht            history_thread.frames[1].GetLineEntry().GetLine(),
9499451b44SJordan Rupprecht            self.line_malloc)
9599451b44SJordan Rupprecht
9699451b44SJordan Rupprecht        # let's free the container (SBThreadCollection) and see if the
9799451b44SJordan Rupprecht        # SBThreads still live
9899451b44SJordan Rupprecht        threads = None
9999451b44SJordan Rupprecht        self.assertTrue(history_thread.num_frames >= 2)
10099451b44SJordan Rupprecht        self.assertEqual(history_thread.frames[1].GetLineEntry(
10199451b44SJordan Rupprecht        ).GetFileSpec().GetFilename(), "main.c")
10299451b44SJordan Rupprecht        self.assertEqual(
10399451b44SJordan Rupprecht            history_thread.frames[1].GetLineEntry().GetLine(),
10499451b44SJordan Rupprecht            self.line_malloc)
10599451b44SJordan Rupprecht
10699451b44SJordan Rupprecht        # ASan will break when a report occurs and we'll try the API then
10799451b44SJordan Rupprecht        self.runCmd("continue")
10899451b44SJordan Rupprecht
10999451b44SJordan Rupprecht        self.expect(
11099451b44SJordan Rupprecht            "thread list",
11199451b44SJordan Rupprecht            "Process should be stopped due to ASan report",
11299451b44SJordan Rupprecht            substrs=[
11399451b44SJordan Rupprecht                'stopped',
11499451b44SJordan Rupprecht                'stop reason = Use of deallocated memory'])
11599451b44SJordan Rupprecht
11699451b44SJordan Rupprecht        # make sure the 'memory history' command still works even when we're
11799451b44SJordan Rupprecht        # generating a report now
11899451b44SJordan Rupprecht        self.expect(
11999451b44SJordan Rupprecht            "memory history 'another_pointer'",
12099451b44SJordan Rupprecht            substrs=[
12199451b44SJordan Rupprecht                'Memory allocated by Thread',
12299451b44SJordan Rupprecht                'a.out`f1',
12399451b44SJordan Rupprecht                'main.c:%d' %
12499451b44SJordan Rupprecht                self.line_malloc2])
125