diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index c0ea53e4a8cbb..95e51408dbcdc 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -364,8 +364,11 @@ bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) { } if (!done) { - StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID(); - done = !(frame_zero_id < m_step_out_to_id); + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + if (stop_info && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) { + StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID(); + done = !(frame_zero_id < m_step_out_to_id); + } } // The normal step out computations think we are done, so all we need to do diff --git a/lldb/test/API/functionalities/thread/finish-from-empty-func/Makefile b/lldb/test/API/functionalities/thread/finish-from-empty-func/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/functionalities/thread/finish-from-empty-func/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/functionalities/thread/finish-from-empty-func/TestEmptyFuncThreadStepOut.py b/lldb/test/API/functionalities/thread/finish-from-empty-func/TestEmptyFuncThreadStepOut.py new file mode 100644 index 0000000000000..bf57070e336e7 --- /dev/null +++ b/lldb/test/API/functionalities/thread/finish-from-empty-func/TestEmptyFuncThreadStepOut.py @@ -0,0 +1,43 @@ +""" +Test finish out of an empty function (may be one-instruction long) +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class FinishFromEmptyFunctionTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def test_finish_from_empty_function(self): + """Test that when stopped at a breakpoint in an empty function, finish leaves it correctly.""" + self.build() + exe = self.getBuildArtifact("a.out") + target, process, thread, _ = lldbutil.run_to_name_breakpoint( + self, "done", exe_name=exe + ) + if self.TraceOn(): + self.runCmd("bt") + + correct_stepped_out_line = line_number("main.c", "leaving main") + return_statement_line = line_number("main.c", "return 0") + safety_bp = target.BreakpointCreateByLocation( + lldb.SBFileSpec("main.c"), return_statement_line + ) + self.assertTrue(safety_bp.IsValid()) + + error = lldb.SBError() + thread.StepOut(error) + self.assertTrue(error.Success()) + + if self.TraceOn(): + self.runCmd("bt") + + frame = thread.GetSelectedFrame() + self.assertEqual( + frame.line_entry.GetLine(), + correct_stepped_out_line, + "Step-out lost control of execution, ran too far", + ) diff --git a/lldb/test/API/functionalities/thread/finish-from-empty-func/main.c b/lldb/test/API/functionalities/thread/finish-from-empty-func/main.c new file mode 100644 index 0000000000000..bc66a548a89df --- /dev/null +++ b/lldb/test/API/functionalities/thread/finish-from-empty-func/main.c @@ -0,0 +1,8 @@ +#include +void done() {} +int main() { + puts("in main"); + done(); + puts("leaving main"); + return 0; +}