浏览代码

Debugger: Fix threads request segfault after thread exited event

Fixes: #25041
Ben McMorran 2 年之前
父节点
当前提交
764258771a
共有 2 个文件被更改,包括 39 次插入5 次删除
  1. 10 4
      Source/cmDebuggerAdapter.cxx
  2. 29 1
      Tests/CMakeLib/testDebuggerAdapter.cxx

+ 10 - 4
Source/cmDebuggerAdapter.cxx

@@ -167,10 +167,16 @@ cmDebuggerAdapter::cmDebuggerAdapter(
     (void)req;
     std::unique_lock<std::mutex> 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;
   });
 

+ 29 - 1
Tests/CMakeLib/testDebuggerAdapter.cxx

@@ -53,7 +53,7 @@ public:
   std::shared_ptr<dap::ReaderWriter> DebuggerToClient;
 };
 
-bool testBasicProtocol()
+bool runTest(std::function<bool(dap::Session&)> onThreadExitedEvent)
 {
   std::promise<bool> debuggerAdapterInitializedPromise;
   std::future<bool> 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<std::function<bool()>>{
     testBasicProtocol,
+    testThreadsRequestAfterThreadExitedEvent,
   });
 }