https://github.com/JDevlieghere updated 
https://github.com/llvm/llvm-project/pull/195959

>From 4b6a5d530e3bdacf25673e890912ff9de855759b Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Tue, 5 May 2026 15:58:21 -0700
Subject: [PATCH 1/3] [lldb] Handle SIGINT via the MainLoop signal thread (on
 POSIX)

The driver's async SIGINT handler called
SBDebugger::DispatchInputInterrupt directly, which is not
async-signal-safe and can lead to a crash.

Register SIGINT with the existing signal-thread MainLoop instead so
DispatchInputInterrupt runs in normal thread context. The callback
temporarily installs SIG_DFL for the duration of DispatchInputInterrupt,
preserving the "second Ctrl-C force-exits" escape hatch users rely on
when the debugger is unresponsive. Windows keeps the existing code path.

rdar://158218595
---
 lldb/tools/driver/Driver.cpp | 34 ++++++++++++++++++++++++++++++----
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index d47d3daf1c3fc..4e25df66fd19b 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -651,11 +651,10 @@ void Driver::UpdateWindowSize() {
   }
 }
 
-void sigint_handler(int signo) {
 #ifdef _WIN32
+void sigint_handler(int signo) {
   // Restore handler as it is not persistent on Windows.
   signal(SIGINT, sigint_handler);
-#endif
 
   static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
   if (g_driver != nullptr) {
@@ -668,6 +667,7 @@ void sigint_handler(int signo) {
 
   _exit(signo);
 }
+#endif
 
 static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
   std::string usage_str = tool_name.str() + " [options]";
@@ -781,15 +781,41 @@ int main(int argc, char const *argv[]) {
   // Setup LLDB signal handlers once the debugger has been initialized.
   SBDebugger::PrintDiagnosticsOnError();
 
-  //  FIXME: Migrate the SIGINT handler to be handled by the signal loop below.
+#ifdef _WIN32
   signal(SIGINT, sigint_handler);
-#if !defined(_WIN32)
+#else
   signal(SIGPIPE, SIG_IGN);
 
   // Handle signals in a MainLoop running on a separate thread.
   MainLoop signal_loop;
   Status signal_status;
 
+  auto sigint_handler = signal_loop.RegisterSignal(
+      SIGINT,
+      [&](MainLoopBase &) {
+        // Temporarily restore the default disposition so that a second SIGINT
+        // delivered while DispatchInputInterrupt is running hard-terminates
+        // the process. This preserves the "double Ctrl-C to force exit"
+        // escape hatch users rely on when the debugger is unresponsive.
+        struct sigaction old_action;
+        struct sigaction new_action = {};
+        new_action.sa_handler = SIG_DFL;
+        sigemptyset(&new_action.sa_mask);
+
+        int ret = sigaction(SIGINT, &new_action, &old_action);
+        UNUSED_IF_ASSERT_DISABLED(ret);
+        assert(ret == 0 && "sigaction failed");
+
+        if (g_driver)
+          g_driver->GetDebugger().DispatchInputInterrupt();
+
+        ret = sigaction(SIGINT, &old_action, nullptr);
+        UNUSED_IF_ASSERT_DISABLED(ret);
+        assert(ret == 0 && "sigaction failed");
+      },
+      signal_status);
+  assert(sigint_handler && signal_status.Success());
+
   auto sigwinch_handler = signal_loop.RegisterSignal(
       SIGWINCH,
       [&](MainLoopBase &) {

>From c2593d2485d5a42dc3397633986114b38d465144 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Tue, 5 May 2026 20:15:07 -0700
Subject: [PATCH 2/3] Install a no-op SIGURG handler

---
 lldb/tools/driver/Driver.cpp | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index 4e25df66fd19b..c1462911011e1 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -43,6 +43,9 @@
 #include <clocale>
 #include <csignal>
 #include <future>
+#ifndef _WIN32
+#include <pthread.h>
+#endif
 #include <string>
 #include <thread>
 #include <utility>
@@ -786,13 +789,25 @@ int main(int argc, char const *argv[]) {
 #else
   signal(SIGPIPE, SIG_IGN);
 
+  // Install a no-op handler for SIGURG so the signal thread can use
+  // pthread_kill(main_tid, SIGURG) to interrupt blocking syscalls (e.g.
+  // Python's time.sleep or input()) on the main thread without causing the
+  // process to terminate or re-entering the SIGINT callback.
+  struct sigaction wakeup_action = {};
+  wakeup_action.sa_handler = [](int) {};
+  sigemptyset(&wakeup_action.sa_mask);
+  sigaction(SIGURG, &wakeup_action, nullptr);
+
+  // Capture the main thread's id so the signal thread can target it.
+  pthread_t main_thread = pthread_self();
+
   // Handle signals in a MainLoop running on a separate thread.
   MainLoop signal_loop;
   Status signal_status;
 
   auto sigint_handler = signal_loop.RegisterSignal(
       SIGINT,
-      [&](MainLoopBase &) {
+      [&, main_thread](MainLoopBase &) {
         // Temporarily restore the default disposition so that a second SIGINT
         // delivered while DispatchInputInterrupt is running hard-terminates
         // the process. This preserves the "double Ctrl-C to force exit"
@@ -812,6 +827,12 @@ int main(int argc, char const *argv[]) {
         ret = sigaction(SIGINT, &old_action, nullptr);
         UNUSED_IF_ASSERT_DISABLED(ret);
         assert(ret == 0 && "sigaction failed");
+
+        // Wake the main thread so any blocking syscall (e.g. the Python REPL
+        // waiting on input or sleeping) returns with EINTR. This lets Python
+        // observe the pending interrupt queued by DispatchInputInterrupt and
+        // raise KeyboardInterrupt.
+        pthread_kill(main_thread, SIGURG);
       },
       signal_status);
   assert(sigint_handler && signal_status.Success());

>From 6a4942dc6529cb3063e9a9845b1a0f8254660c48 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Thu, 7 May 2026 10:41:10 -0700
Subject: [PATCH 3/3] Go with Pavel's suggestion to use SIGINT

---
 lldb/tools/driver/Driver.cpp | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index c1462911011e1..95c1c6601479e 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -789,18 +789,13 @@ int main(int argc, char const *argv[]) {
 #else
   signal(SIGPIPE, SIG_IGN);
 
-  // Install a no-op handler for SIGURG so the signal thread can use
-  // pthread_kill(main_tid, SIGURG) to interrupt blocking syscalls (e.g.
-  // Python's time.sleep or input()) on the main thread without causing the
-  // process to terminate or re-entering the SIGINT callback.
-  struct sigaction wakeup_action = {};
-  wakeup_action.sa_handler = [](int) {};
-  sigemptyset(&wakeup_action.sa_mask);
-  sigaction(SIGURG, &wakeup_action, nullptr);
-
   // Capture the main thread's id so the signal thread can target it.
   pthread_t main_thread = pthread_self();
 
+  // Set when the signal thread sends itself a SIGINT to wake the main thread.
+  // The next SIGINT callback invocation observes this flag and skips the work.
+  std::atomic<bool> skip_next_sigint{false};
+
   // Handle signals in a MainLoop running on a separate thread.
   MainLoop signal_loop;
   Status signal_status;
@@ -808,6 +803,11 @@ int main(int argc, char const *argv[]) {
   auto sigint_handler = signal_loop.RegisterSignal(
       SIGINT,
       [&, main_thread](MainLoopBase &) {
+        // Skip the self-sent wakeup SIGINT queued at the end of the previous
+        // invocation.
+        if (skip_next_sigint.exchange(false))
+          return;
+
         // Temporarily restore the default disposition so that a second SIGINT
         // delivered while DispatchInputInterrupt is running hard-terminates
         // the process. This preserves the "double Ctrl-C to force exit"
@@ -831,8 +831,10 @@ int main(int argc, char const *argv[]) {
         // Wake the main thread so any blocking syscall (e.g. the Python REPL
         // waiting on input or sleeping) returns with EINTR. This lets Python
         // observe the pending interrupt queued by DispatchInputInterrupt and
-        // raise KeyboardInterrupt.
-        pthread_kill(main_thread, SIGURG);
+        // raise KeyboardInterrupt. Flag the resulting callback invocation so
+        // it's skipped rather than re-running DispatchInputInterrupt.
+        skip_next_sigint.store(true);
+        pthread_kill(main_thread, SIGINT);
       },
       signal_status);
   assert(sigint_handler && signal_status.Success());

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to