Skip to content

Commit 23c9ec9

Browse files
committed
Fix the run locker setting for async launches that don't stop at the
initial stop. The code was using PrivateResume when it should have used Resume. This was allowing expression evaluation while the target was running, and though that was caught a litle later on, we should never have gotten that far. To make sure that this is caught immediately I made an error SBValue when this happens, and test that we get this error. Differential Revision: https://reviews.llvm.org/D144665 (cherry picked from commit a92f783) (cherry picked from commit 86a538e)
1 parent 84ec9db commit 23c9ec9

File tree

6 files changed

+152
-8
lines changed

6 files changed

+152
-8
lines changed

lldb/source/API/SBFrame.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "lldb/Core/StructuredDataImpl.h"
2121
#include "lldb/Core/ValueObjectRegister.h"
2222
#include "lldb/Core/ValueObjectVariable.h"
23+
#include "lldb/Core/ValueObjectConstResult.h"
2324
#include "lldb/Expression/ExpressionVariable.h"
2425
#include "lldb/Expression/UserExpression.h"
2526
#include "lldb/Host/Host.h"
@@ -997,6 +998,12 @@ SBValue SBFrame::EvaluateExpression(const char *expr) {
997998
else
998999
options.SetLanguage(frame->GetLanguage());
9991000
return EvaluateExpression(expr, options);
1001+
} else {
1002+
Status error;
1003+
error.SetErrorString("can't evaluate expressions when the "
1004+
"process is running.");
1005+
ValueObjectSP error_val_sp = ValueObjectConstResult::Create(nullptr, error);
1006+
result.SetSP(error_val_sp, false);
10001007
}
10011008
return result;
10021009
}
@@ -1060,7 +1067,6 @@ lldb::SBValue SBFrame::EvaluateExpression(const char *expr,
10601067
std::unique_lock<std::recursive_mutex> lock;
10611068
ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
10621069

1063-
10641070
StackFrame *frame = nullptr;
10651071
Target *target = exe_ctx.GetTargetPtr();
10661072
Process *process = exe_ctx.GetProcessPtr();
@@ -1084,13 +1090,30 @@ lldb::SBValue SBFrame::EvaluateExpression(const char *expr,
10841090
target->EvaluateExpression(expr, frame, expr_value_sp, options.ref());
10851091
expr_result.SetSP(expr_value_sp, options.GetFetchDynamicValue());
10861092
}
1093+
} else {
1094+
Status error;
1095+
error.SetErrorString("can't evaluate expressions when the "
1096+
"process is running.");
1097+
expr_value_sp = ValueObjectConstResult::Create(nullptr, error);
1098+
expr_result.SetSP(expr_value_sp, false);
10871099
}
1100+
} else {
1101+
Status error;
1102+
error.SetErrorString("sbframe object is not valid.");
1103+
expr_value_sp = ValueObjectConstResult::Create(nullptr, error);
1104+
expr_result.SetSP(expr_value_sp, false);
10881105
}
10891106

1090-
LLDB_LOGF(expr_log,
1091-
"** [SBFrame::EvaluateExpression] Expression result is "
1092-
"%s, summary %s **",
1093-
expr_result.GetValue(), expr_result.GetSummary());
1107+
if (expr_result.GetError().Success())
1108+
LLDB_LOGF(expr_log,
1109+
"** [SBFrame::EvaluateExpression] Expression result is "
1110+
"%s, summary %s **",
1111+
expr_result.GetValue(), expr_result.GetSummary());
1112+
else
1113+
LLDB_LOGF(expr_log,
1114+
"** [SBFrame::EvaluateExpression] Expression evaluation failed: "
1115+
"%s **",
1116+
expr_result.GetError().GetCString());
10941117

10951118
return expr_result;
10961119
}

lldb/source/API/SBTarget.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,12 +2278,25 @@ lldb::SBValue SBTarget::EvaluateExpression(const char *expr,
22782278
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
22792279
ExecutionContext exe_ctx(m_opaque_sp.get());
22802280

2281-
22822281
frame = exe_ctx.GetFramePtr();
22832282
Target *target = exe_ctx.GetTargetPtr();
2283+
Process *process = exe_ctx.GetProcessPtr();
22842284

22852285
if (target) {
2286-
target->EvaluateExpression(expr, frame, expr_value_sp, options.ref());
2286+
// If we have a process, make sure to lock the runlock:
2287+
if (process) {
2288+
Process::StopLocker stop_locker;
2289+
if (stop_locker.TryLock(&process->GetRunLock())) {
2290+
target->EvaluateExpression(expr, frame, expr_value_sp, options.ref());
2291+
} else {
2292+
Status error;
2293+
error.SetErrorString("can't evaluate expressions when the "
2294+
"process is running.");
2295+
expr_value_sp = ValueObjectConstResult::Create(nullptr, error);
2296+
}
2297+
} else {
2298+
target->EvaluateExpression(expr, frame, expr_value_sp, options.ref());
2299+
}
22872300

22882301
expr_result.SetSP(expr_value_sp, options.GetFetchDynamicValue());
22892302
}

lldb/source/Target/Target.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3627,7 +3627,7 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) {
36273627
// SyncResume hijacker.
36283628
m_process_sp->ResumeSynchronous(stream);
36293629
else
3630-
error = m_process_sp->PrivateResume();
3630+
error = m_process_sp->Resume();
36313631
if (!error.Success()) {
36323632
Status error2;
36333633
error2.SetErrorStringWithFormat(
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
C_SOURCES := main.c
2+
CFLAGS_EXTRAS := -std=c99
3+
4+
include Makefile.rules
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
"""
2+
Test that the run locker really does work to keep
3+
us from running SB API that should only be run
4+
while stopped. This test is mostly concerned with
5+
what happens between launch and first stop.
6+
"""
7+
8+
import lldb
9+
import lldbsuite.test.lldbutil as lldbutil
10+
from lldbsuite.test.lldbtest import *
11+
12+
13+
class TestRunLocker(TestBase):
14+
15+
NO_DEBUG_INFO_TESTCASE = True
16+
17+
def test_run_locker(self):
18+
"""Test that the run locker is set correctly when we launch"""
19+
self.build()
20+
self.runlocker_test(False)
21+
22+
def test_run_locker_stop_at_entry(self):
23+
"""Test that the run locker is set correctly when we launch"""
24+
self.build()
25+
self.runlocker_test(False)
26+
27+
def setUp(self):
28+
# Call super's setUp().
29+
TestBase.setUp(self)
30+
self.main_source_file = lldb.SBFileSpec("main.c")
31+
32+
def runlocker_test(self, stop_at_entry):
33+
"""The code to stop at entry handles events slightly differently, so
34+
we test both versions of process launch."""
35+
36+
target = lldbutil.run_to_breakpoint_make_target(self)
37+
38+
launch_info = target.GetLaunchInfo()
39+
if stop_at_entry:
40+
flags = launch_info.GetFlags()
41+
launch_info.SetFlags(flags | lldb.eLaunchFlagStopAtEntry)
42+
43+
error = lldb.SBError()
44+
# We are trying to do things when the process is running, so
45+
# we have to run the debugger asynchronously.
46+
self.dbg.SetAsync(True)
47+
48+
listener = lldb.SBListener("test-run-lock-listener")
49+
launch_info.SetListener(listener)
50+
process = target.Launch(launch_info, error)
51+
self.assertSuccess(error, "Launched the process")
52+
53+
event = lldb.SBEvent()
54+
55+
event_result = listener.WaitForEvent(10, event)
56+
self.assertTrue(event_result, "timed out waiting for launch")
57+
state_type = lldb.SBProcess.GetStateFromEvent(event)
58+
# We don't always see a launching...
59+
if state_type == lldb.eStateLaunching:
60+
event_result = listener.WaitForEvent(10, event)
61+
self.assertTrue(event_result, "Timed out waiting for running after launching")
62+
state_type = lldb.SBProcess.GetStateFromEvent(event)
63+
64+
self.assertState(state_type, lldb.eStateRunning, "Didn't get a running event")
65+
66+
# We aren't checking the entry state, but just making sure
67+
# the running state is set properly if we continue in this state.
68+
69+
if stop_at_entry:
70+
event_result = listener.WaitForEvent(10, event)
71+
self.assertTrue(event_result, "Timed out waiting for stop at entry stop")
72+
state_type = lldb.SBProcess.GetStateFromEvent(event)
73+
self.assertState(state_type, eStateStopped, "Stop at entry stopped")
74+
process.Continue()
75+
76+
# Okay, now the process is running, make sure we can't do things
77+
# you aren't supposed to do while running, and that we get some
78+
# actual error:
79+
val = target.EvaluateExpression("SomethingToCall()")
80+
error = val.GetError()
81+
self.assertTrue(error.Fail(), "Failed to run expression")
82+
print(f"Got Error: {error.GetCString()}")
83+
self.assertIn("can't evaluate expressions when the process is running", error.GetCString(), "Stopped by stop locker")
84+
85+
# This should also fail if we try to use the script interpreter directly:
86+
interp = self.dbg.GetCommandInterpreter()
87+
result = lldb.SBCommandReturnObject()
88+
ret = interp.HandleCommand("script var = lldb.frame.EvaluateExpression('SomethingToCall()'); var.GetError().GetCString()", result)
89+
self.assertIn("can't evaluate expressions when the process is running", result.GetOutput())
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <unistd.h>
2+
3+
int
4+
SomethingToCall() {
5+
return 100;
6+
}
7+
8+
int
9+
main()
10+
{
11+
while (1) {
12+
sleep(1);
13+
}
14+
return SomethingToCall();
15+
}

0 commit comments

Comments
 (0)