reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
"""
Test that ASan memory history provider returns correct stack traces
"""

from __future__ import print_function


import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbplatform
from lldbsuite.test import lldbutil


class AsanTestCase(TestBase):

    mydir = TestBase.compute_mydir(__file__)

    @skipIfFreeBSD  # llvm.org/pr21136 runtimes not yet available by default
    @skipIfRemote
    @skipUnlessAddressSanitizer
    def test(self):
        self.build()
        self.asan_tests()

    def setUp(self):
        # Call super's setUp().
        TestBase.setUp(self)
        self.line_malloc = line_number('main.c', '// malloc line')
        self.line_malloc2 = line_number('main.c', '// malloc2 line')
        self.line_free = line_number('main.c', '// free line')
        self.line_breakpoint = line_number('main.c', '// break line')

    def asan_tests(self):
        exe = self.getBuildArtifact("a.out")
        self.expect(
            "file " + exe,
            patterns=["Current executable set to .*a.out"])

        self.runCmd("breakpoint set -f main.c -l %d" % self.line_breakpoint)

        # "memory history" command should not work without a process
        self.expect("memory history 0",
                    error=True,
                    substrs=["invalid process"])

        self.runCmd("run")

        stop_reason = self.dbg.GetSelectedTarget().process.GetSelectedThread().GetStopReason()
        if stop_reason == lldb.eStopReasonExec:
            # On OS X 10.10 and older, we need to re-exec to enable
            # interceptors.
            self.runCmd("continue")

        # the stop reason of the thread should be breakpoint.
        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
                    substrs=['stopped', 'stop reason = breakpoint'])

        # test that the ASan dylib is present
        self.expect(
            "image lookup -n __asan_describe_address",
            "__asan_describe_address should be present",
            substrs=['1 match found'])

        # test the 'memory history' command
        self.expect(
            "memory history 'pointer'",
            substrs=[
                'Memory allocated by Thread',
                'a.out`f1',
                'main.c:%d' %
                self.line_malloc,
                'Memory deallocated by Thread',
                'a.out`f2',
                'main.c:%d' %
                self.line_free])

        # do the same using SB API
        process = self.dbg.GetSelectedTarget().process
        val = process.GetSelectedThread().GetSelectedFrame().EvaluateExpression("pointer")
        addr = val.GetValueAsUnsigned()
        threads = process.GetHistoryThreads(addr)
        self.assertEqual(threads.GetSize(), 2)

        history_thread = threads.GetThreadAtIndex(0)
        self.assertTrue(history_thread.num_frames >= 2)
        self.assertEqual(history_thread.frames[1].GetLineEntry(
        ).GetFileSpec().GetFilename(), "main.c")
        self.assertEqual(
            history_thread.frames[1].GetLineEntry().GetLine(),
            self.line_free)

        history_thread = threads.GetThreadAtIndex(1)
        self.assertTrue(history_thread.num_frames >= 2)
        self.assertEqual(history_thread.frames[1].GetLineEntry(
        ).GetFileSpec().GetFilename(), "main.c")
        self.assertEqual(
            history_thread.frames[1].GetLineEntry().GetLine(),
            self.line_malloc)

        # let's free the container (SBThreadCollection) and see if the
        # SBThreads still live
        threads = None
        self.assertTrue(history_thread.num_frames >= 2)
        self.assertEqual(history_thread.frames[1].GetLineEntry(
        ).GetFileSpec().GetFilename(), "main.c")
        self.assertEqual(
            history_thread.frames[1].GetLineEntry().GetLine(),
            self.line_malloc)

        # ASan will break when a report occurs and we'll try the API then
        self.runCmd("continue")

        self.expect(
            "thread list",
            "Process should be stopped due to ASan report",
            substrs=[
                'stopped',
                'stop reason = Use of deallocated memory'])

        # make sure the 'memory history' command still works even when we're
        # generating a report now
        self.expect(
            "memory history 'another_pointer'",
            substrs=[
                'Memory allocated by Thread',
                'a.out`f1',
                'main.c:%d' %
                self.line_malloc2])