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