Skip to content

Commit af1b036

Browse files
authored
Merge pull request #2927 from jimingham/no-more-packets
When SendContinuePacketAndWaitForResponse returns eStateInvalid, don'…
2 parents 8d4a055 + ed20300 commit af1b036

File tree

2 files changed

+87
-1
lines changed

2 files changed

+87
-1
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3665,12 +3665,25 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) {
36653665
__FUNCTION__, arg, process->GetID());
36663666

36673667
EventSP event_sp;
3668+
3669+
// We need to ignore any packets that come in after we have
3670+
// have decided the process has exited. There are some
3671+
// situations, for instance when we try to interrupt a running
3672+
// process and the interrupt fails, where another packet might
3673+
// get delivered after we've decided to give up on the process.
3674+
// But once we've decided we are done with the process we will
3675+
// not be in a state to do anything useful with new packets.
3676+
// So it is safer to simply ignore any remaining packets by
3677+
// explicitly checking for eStateExited before reentering the
3678+
// fetch loop.
3679+
36683680
bool done = false;
3669-
while (!done) {
3681+
while (!done && process->GetPrivateState() != eStateExited) {
36703682
LLDB_LOGF(log,
36713683
"ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64
36723684
") listener.WaitForEvent (NULL, event_sp)...",
36733685
__FUNCTION__, arg, process->GetID());
3686+
36743687
if (process->m_async_listener_sp->GetEvent(event_sp, llvm::None)) {
36753688
const uint32_t event_type = event_sp->GetType();
36763689
if (event_sp->BroadcasterIs(&process->m_async_broadcaster)) {
@@ -3769,6 +3782,7 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) {
37693782
} else {
37703783
process->SetExitStatus(-1, "lost connection");
37713784
}
3785+
done = true;
37723786
break;
37733787
}
37743788

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from __future__ import print_function
2+
import lldb
3+
from lldbsuite.test.lldbtest import *
4+
from lldbsuite.test.decorators import *
5+
from gdbclientutils import *
6+
7+
8+
class TestHaltFails(GDBRemoteTestBase):
9+
10+
class MyResponder(MockGDBServerResponder):
11+
12+
def setBreakpoint(self, packet):
13+
return "OK"
14+
15+
def interrupt(self):
16+
# Simulate process waiting longer than the interrupt
17+
# timeout to stop, then sending the reply.
18+
time.sleep(14)
19+
return "T02reason:signal"
20+
21+
def cont(self):
22+
# No response, wait for the client to interrupt us.
23+
return None
24+
25+
def wait_for_and_check_event(self, wait_time, value):
26+
event = lldb.SBEvent()
27+
got_event = self.dbg.GetListener().WaitForEvent(wait_time, event)
28+
self.assertTrue(got_event, "Failed to get event after wait")
29+
self.assertTrue(lldb.SBProcess.EventIsProcessEvent(event), "Event was not a process event")
30+
event_type = lldb.SBProcess.GetStateFromEvent(event)
31+
self.assertEqual(event_type, value)
32+
33+
def get_to_running(self):
34+
self.server.responder = self.MyResponder()
35+
self.target = self.createTarget("a.yaml")
36+
process = self.connect(self.target)
37+
self.dbg.SetAsync(True)
38+
39+
# There should be a stopped event, consume that:
40+
self.wait_for_and_check_event(2, lldb.eStateStopped)
41+
process.Continue()
42+
43+
# There should be a running event, consume that:
44+
self.wait_for_and_check_event(2, lldb.eStateRunning)
45+
return process
46+
47+
@skipIfReproducer # FIXME: Unexpected packet during (passive) replay
48+
def test_destroy_while_running(self):
49+
process = self.get_to_running()
50+
process.Destroy()
51+
52+
# Again pretend that after failing to be interrupted, we delivered the stop
53+
# and make sure we still exit properly.
54+
self.wait_for_and_check_event(14, lldb.eStateExited)
55+
56+
@skipIfReproducer # FIXME: Unexpected packet during (passive) replay
57+
def test_async_interrupt(self):
58+
"""
59+
Test that explicitly calling AsyncInterrupt, which then fails, leads
60+
to an "eStateExited" state.
61+
"""
62+
process = self.get_to_running()
63+
# Now do the interrupt:
64+
process.SendAsyncInterrupt()
65+
66+
# That should have caused the Halt to time out and we should
67+
# be in eStateExited:
68+
self.wait_for_and_check_event(15, lldb.eStateExited)
69+
70+
71+
72+

0 commit comments

Comments
 (0)