Skip to content

Commit 9d3aec5

Browse files
authored
Fix a stall in running quit while a live process is running (llvm#74687)
We need to generate events when finalizing, or we won't know that we succeeded in stopping the process to detach/kill. Instead, we stall and then after our 20 interrupt timeout, we kill the process (even if we were supposed to detach) and exit. OTOH, we have to not generate events when the Process is being destructed because shared_from_this has already been torn down, and using it will cause crashes.
1 parent 4a6ed4a commit 9d3aec5

File tree

14 files changed

+74
-13
lines changed

14 files changed

+74
-13
lines changed

lldb/include/lldb/Target/Process.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,10 @@ class Process : public std::enable_shared_from_this<Process>,
558558
///
559559
/// Subclasses that override this method should always call this superclass
560560
/// method.
561-
virtual void Finalize();
561+
/// If you are running Finalize in your Process subclass Destructor, pass
562+
/// \b true. If we are in the destructor, shared_from_this will no longer
563+
/// work, so we have to avoid doing anything that might trigger that.
564+
virtual void Finalize(bool destructing);
562565

563566
/// Return whether this object is valid (i.e. has not been finalized.)
564567
///
@@ -3079,6 +3082,11 @@ void PruneThreadPlans();
30793082
/// This is set at the beginning of Process::Finalize() to stop functions
30803083
/// from looking up or creating things during or after a finalize call.
30813084
std::atomic<bool> m_finalizing;
3085+
// When we are "Finalizing" we need to do some cleanup. But if the Finalize
3086+
// call is coming in the Destructor, we can't do any actual work in the
3087+
// process because that is likely to call "shared_from_this" which crashes
3088+
// if run while destructing. We use this flag to determine that.
3089+
std::atomic<bool> m_destructing;
30823090

30833091
/// Mask for code an data addresses. The default value (0) means no mask is
30843092
/// set. The bits set to 1 indicate bits that are NOT significant for

lldb/source/Core/Debugger.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,7 @@ void Debugger::Clear() {
930930
for (TargetSP target_sp : m_target_list.Targets()) {
931931
if (target_sp) {
932932
if (ProcessSP process_sp = target_sp->GetProcessSP())
933-
process_sp->Finalize();
933+
process_sp->Finalize(false /* not destructing */);
934934
target_sp->Destroy();
935935
}
936936
}

lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ ProcessKDP::~ProcessKDP() {
164164
// make sure all of the broadcaster cleanup goes as planned. If we destruct
165165
// this class, then Process::~Process() might have problems trying to fully
166166
// destroy the broadcaster.
167-
Finalize();
167+
Finalize(true /* destructing */);
168168
}
169169

170170
Status ProcessKDP::DoWillLaunch(Module *module) {

lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ ProcessElfCore::~ProcessElfCore() {
108108
// make sure all of the broadcaster cleanup goes as planned. If we destruct
109109
// this class, then Process::~Process() might have problems trying to fully
110110
// destroy the broadcaster.
111-
Finalize();
111+
Finalize(true /* destructing */);
112112
}
113113

114114
lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment(

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ ProcessGDBRemote::~ProcessGDBRemote() {
303303
// make sure all of the broadcaster cleanup goes as planned. If we destruct
304304
// this class, then Process::~Process() might have problems trying to fully
305305
// destroy the broadcaster.
306-
Finalize();
306+
Finalize(true /* destructing */);
307307

308308
// The general Finalize is going to try to destroy the process and that
309309
// SHOULD shut down the async thread. However, if we don't kill it it will

lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ ProcessMachCore::~ProcessMachCore() {
123123
// make sure all of the broadcaster cleanup goes as planned. If we destruct
124124
// this class, then Process::~Process() might have problems trying to fully
125125
// destroy the broadcaster.
126-
Finalize();
126+
Finalize(true /* destructing */);
127127
}
128128

129129
bool ProcessMachCore::CheckAddressForDyldOrKernel(lldb::addr_t addr,

lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ ProcessMinidump::~ProcessMinidump() {
166166
// make sure all of the broadcaster cleanup goes as planned. If we destruct
167167
// this class, then Process::~Process() might have problems trying to fully
168168
// destroy the broadcaster.
169-
Finalize();
169+
Finalize(true /* destructing */);
170170
}
171171

172172
void ProcessMinidump::Initialize() {

lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ ScriptedProcess::~ScriptedProcess() {
140140
// make sure all of the broadcaster cleanup goes as planned. If we destruct
141141
// this class, then Process::~Process() might have problems trying to fully
142142
// destroy the broadcaster.
143-
Finalize();
143+
Finalize(true /* destructing */);
144144
}
145145

146146
void ScriptedProcess::Initialize() {

lldb/source/Target/Process.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp,
445445
m_memory_cache(*this), m_allocated_memory_cache(*this),
446446
m_should_detach(false), m_next_event_action_up(), m_public_run_lock(),
447447
m_private_run_lock(), m_currently_handling_do_on_removals(false),
448-
m_resume_requested(false), m_finalizing(false),
448+
m_resume_requested(false), m_finalizing(false), m_destructing(false),
449449
m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false),
450450
m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false),
451451
m_can_interpret_function_calls(false), m_run_thread_plan_lock(),
@@ -518,9 +518,11 @@ ProcessProperties &Process::GetGlobalProperties() {
518518
return *g_settings_ptr;
519519
}
520520

521-
void Process::Finalize() {
521+
void Process::Finalize(bool destructing) {
522522
if (m_finalizing.exchange(true))
523523
return;
524+
if (destructing)
525+
m_destructing.exchange(true);
524526

525527
// Destroy the process. This will call the virtual function DoDestroy under
526528
// the hood, giving our derived class a chance to do the ncessary tear down.
@@ -1415,7 +1417,13 @@ bool Process::StateChangedIsHijackedForSynchronousResume() {
14151417
StateType Process::GetPrivateState() { return m_private_state.GetValue(); }
14161418

14171419
void Process::SetPrivateState(StateType new_state) {
1418-
if (m_finalizing)
1420+
// Use m_destructing not m_finalizing here. If we are finalizing a process
1421+
// that we haven't started tearing down, we'd like to be able to nicely
1422+
// detach if asked, but that requires the event system be live. That will
1423+
// not be true for an in-the-middle-of-being-destructed Process, since the
1424+
// event system relies on Process::shared_from_this, which may have already
1425+
// been destroyed.
1426+
if (m_destructing)
14191427
return;
14201428

14211429
Log *log(GetLog(LLDBLog::State | LLDBLog::Process | LLDBLog::Unwind));

lldb/source/Target/ProcessTrace.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ ProcessTrace::~ProcessTrace() {
5050
// make sure all of the broadcaster cleanup goes as planned. If we destruct
5151
// this class, then Process::~Process() might have problems trying to fully
5252
// destroy the broadcaster.
53-
Finalize();
53+
Finalize(true /* destructing */);
5454
}
5555

5656
void ProcessTrace::DidAttach(ArchSpec &process_arch) {

lldb/source/Target/Target.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ void Target::DeleteCurrentProcess() {
197197
if (m_process_sp->IsAlive())
198198
m_process_sp->Destroy(false);
199199

200-
m_process_sp->Finalize();
200+
m_process_sp->Finalize(false /* not destructing */);
201201

202202
CleanupProcess();
203203

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
C_SOURCES := main.c
2+
3+
include Makefile.rules
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""
2+
Test that killing the target while quitting doesn't stall
3+
"""
4+
5+
6+
import lldb
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test import lldbutil
10+
import pexpect
11+
from lldbsuite.test.lldbpexpect import PExpectTest
12+
13+
14+
class DriverQuitSpeedTest(PExpectTest):
15+
source = "main.c"
16+
17+
def test_run_quit(self):
18+
"""Test that the lldb driver's batch mode works correctly."""
19+
self.build()
20+
21+
exe = self.getBuildArtifact("a.out")
22+
23+
# Turn on auto-confirm removes the wait for the prompt.
24+
self.launch(executable=exe, extra_args=["-O", "settings set auto-confirm 1"])
25+
child = self.child
26+
27+
# Launch the process without a TTY so we don't have to interrupt:
28+
child.sendline("process launch -n")
29+
print("launched process")
30+
child.expect("Process ([\d]*) launched:")
31+
print("Got launch message")
32+
child.sendline("quit")
33+
print("sent quit")
34+
child.expect(pexpect.EOF, timeout=15)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <unistd.h>
2+
3+
int main (int argc, char **argv) {
4+
while(1)
5+
usleep(5);
6+
7+
return 0;
8+
}

0 commit comments

Comments
 (0)