From 764258771afb92067dd4b2c044d8d19abc6f932c Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Thu, 29 Jun 2023 09:10:46 -0700 Subject: Debugger: Fix threads request segfault after thread exited event Fixes: #25041 --- Source/cmDebuggerAdapter.cxx | 14 ++++++++++---- Tests/CMakeLib/testDebuggerAdapter.cxx | 30 +++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/Source/cmDebuggerAdapter.cxx b/Source/cmDebuggerAdapter.cxx index d03f79d..c2e0d4f 100644 --- a/Source/cmDebuggerAdapter.cxx +++ b/Source/cmDebuggerAdapter.cxx @@ -167,10 +167,16 @@ cmDebuggerAdapter::cmDebuggerAdapter( (void)req; std::unique_lock lock(Mutex); dap::ThreadsResponse response; - dap::Thread thread; - thread.id = DefaultThread->GetId(); - thread.name = DefaultThread->GetName(); - response.threads.push_back(thread); + + // If a client requests threads during shutdown (like after receiving the + // thread exited event), DefaultThread won't be set. + if (DefaultThread) { + dap::Thread thread; + thread.id = DefaultThread->GetId(); + thread.name = DefaultThread->GetName(); + response.threads.push_back(thread); + } + return response; }); diff --git a/Tests/CMakeLib/testDebuggerAdapter.cxx b/Tests/CMakeLib/testDebuggerAdapter.cxx index 394986b..e66d990 100644 --- a/Tests/CMakeLib/testDebuggerAdapter.cxx +++ b/Tests/CMakeLib/testDebuggerAdapter.cxx @@ -53,7 +53,7 @@ public: std::shared_ptr DebuggerToClient; }; -bool testBasicProtocol() +bool runTest(std::function onThreadExitedEvent) { std::promise debuggerAdapterInitializedPromise; std::future debuggerAdapterInitializedFuture = @@ -152,6 +152,11 @@ bool testBasicProtocol() std::future_status::ready); ASSERT_TRUE(threadExitedFuture.wait_for(futureTimeout) == std::future_status::ready); + + if (onThreadExitedEvent) { + ASSERT_TRUE(onThreadExitedEvent(*client)); + } + ASSERT_TRUE(exitedEventReceivedFuture.wait_for(futureTimeout) == std::future_status::ready); ASSERT_TRUE(terminatedEventReceivedFuture.wait_for(futureTimeout) == @@ -165,9 +170,32 @@ bool testBasicProtocol() return true; } +bool testBasicProtocol() +{ + return runTest(nullptr); +} + +bool testThreadsRequestAfterThreadExitedEvent() +{ + return runTest([](dap::Session& session) -> bool { + // Try requesting threads again after receiving the thread exited event. + // Some clients do this to ensure that their thread list is up-to-date. + dap::ThreadsRequest threadsRequest; + auto threadsResponse = session.send(threadsRequest).get(); + ASSERT_TRUE(!threadsResponse.error); + + // CMake only has one DAP thread. Once that thread exits, there should be + // no threads left. + ASSERT_TRUE(threadsResponse.response.threads.empty()); + + return true; + }); +} + int testDebuggerAdapter(int, char*[]) { return runTests(std::vector>{ testBasicProtocol, + testThreadsRequestAfterThreadExitedEvent, }); } -- cgit v0.12