https://github.com/pdepetro created 
https://github.com/llvm/llvm-project/pull/184815

@jimingham You had suggested to @clayborg that we should call DidFork(), 
DidVFork() and DidVForkDone() after a corresponding stop in expression 
evaluation. Those functions require parameters that are private to the specific 
child StopInfo class.  I went with reusing the existing 
StopInfo::PerformAction() virtual function, rather than create a new one just 
for this purpose.

>From ef1fe58c7bc375bb1eb11df926242a82836082d1 Mon Sep 17 00:00:00 2001
From: Philip DePetro <[email protected]>
Date: Thu, 19 Feb 2026 07:45:23 -0800
Subject: [PATCH 1/3] [lldb] Handle forking in expressions

Previously, forking events would cause expression evaluation to stop.
---
 lldb/include/lldb/Target/StopInfo.h           |  1 +
 lldb/source/Target/ThreadPlanCallFunction.cpp | 15 +++++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/lldb/include/lldb/Target/StopInfo.h 
b/lldb/include/lldb/Target/StopInfo.h
index cdd6a6fbe6aa4..5c1f37edcbd3e 100644
--- a/lldb/include/lldb/Target/StopInfo.h
+++ b/lldb/include/lldb/Target/StopInfo.h
@@ -21,6 +21,7 @@ class StopInfo : public 
std::enable_shared_from_this<StopInfo> {
   friend class Process::ProcessEventData;
   friend class ThreadPlanBase;
   friend class ThreadPlanReverseContinue;
+  friend class ThreadPlanCallFunction;
 
 public:
   // Constructors and Destructors
diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp 
b/lldb/source/Target/ThreadPlanCallFunction.cpp
index 218111d4faf60..e555745754aab 100644
--- a/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -284,6 +284,21 @@ bool ThreadPlanCallFunction::DoPlanExplainsStop(Event 
*event_ptr) {
   if (stop_reason == eStopReasonBreakpoint && BreakpointsExplainStop())
     return true;
 
+  if ((stop_reason == eStopReasonFork) ||
+      (stop_reason == eStopReasonVFork) ||
+      (stop_reason == eStopReasonVForkDone)) {
+    if (stop_reason == eStopReasonFork)
+      LLDB_LOGF(log, "ThreadPlanCallFunction::PlanExplainsStop hit a fork not 
stopping.");
+    else if (stop_reason == eStopReasonVFork)
+      LLDB_LOGF(log, "ThreadPlanCallFunction::PlanExplainsStop hit a vfork not 
stopping.");
+    else if (stop_reason == eStopReasonVForkDone)
+      LLDB_LOGF(log, "ThreadPlanCallFunction::PlanExplainsStop hit a vforkdone 
not stopping.");
+
+    m_real_stop_info_sp->PerformAction(event_ptr);
+    m_real_stop_info_sp->OverrideShouldStop(false);
+    return true;
+  }
+
   // One more quirk here.  If this event was from Halt interrupting the target,
   // then we should not consider ourselves complete.  Return true to
   // acknowledge the stop.

>From e4177b490a6ff5d94841606d6cf540ae2a9c4e69 Mon Sep 17 00:00:00 2001
From: Philip DePetro <[email protected]>
Date: Thu, 19 Feb 2026 09:12:35 -0800
Subject: [PATCH 2/3] Add a test for fork in an expression

---
 .../expression/expr-with-fork/Makefile        |  4 +++
 .../expr-with-fork/TestExprWithFork.py        | 33 +++++++++++++++++++
 .../expression/expr-with-fork/main.cpp        | 21 ++++++++++++
 3 files changed, 58 insertions(+)
 create mode 100644 lldb/test/API/commands/expression/expr-with-fork/Makefile
 create mode 100644 
lldb/test/API/commands/expression/expr-with-fork/TestExprWithFork.py
 create mode 100644 lldb/test/API/commands/expression/expr-with-fork/main.cpp

diff --git a/lldb/test/API/commands/expression/expr-with-fork/Makefile 
b/lldb/test/API/commands/expression/expr-with-fork/Makefile
new file mode 100644
index 0000000000000..f016d5b15d839
--- /dev/null
+++ b/lldb/test/API/commands/expression/expr-with-fork/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+USE_SYSTEM_STDLIB := 1
+
+include Makefile.rules
diff --git 
a/lldb/test/API/commands/expression/expr-with-fork/TestExprWithFork.py 
b/lldb/test/API/commands/expression/expr-with-fork/TestExprWithFork.py
new file mode 100644
index 0000000000000..8de07a32ab7cd
--- /dev/null
+++ b/lldb/test/API/commands/expression/expr-with-fork/TestExprWithFork.py
@@ -0,0 +1,33 @@
+"""
+Test that expressions that call functions which fork
+can be evaluated successfully.
+
+This tests the ThreadPlanCallFunction handling of fork/vfork/vforkdone
+stop reasons, which should be silently resumed rather than causing the
+expression evaluation to fail.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ExprWithForkTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipIfWindows
+    @add_test_categories(["fork"])
+    def test_expr_with_fork(self):
+        """Test that expression evaluation succeeds when the expression calls 
fork()."""
+        self.build()
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+
+        # Evaluate an expression that calls fork() inside a user function.
+        # The fork will generate a fork stop event which ThreadPlanCallFunction
+        # must handle transparently for the expression to complete.
+        self.expect_expr(
+            "fork_and_return(42)", result_type="int", result_value="42"
+        )
diff --git a/lldb/test/API/commands/expression/expr-with-fork/main.cpp 
b/lldb/test/API/commands/expression/expr-with-fork/main.cpp
new file mode 100644
index 0000000000000..80565cf6c4420
--- /dev/null
+++ b/lldb/test/API/commands/expression/expr-with-fork/main.cpp
@@ -0,0 +1,21 @@
+#include <sys/wait.h>
+#include <unistd.h>
+
+int fork_and_return(int value) {
+  pid_t pid = fork();
+  if (pid == -1)
+    return -1;
+  if (pid == 0) {
+    // child
+    _exit(0);
+  }
+  // parent
+  int status;
+  waitpid(pid, &status, 0);
+  return value;
+}
+
+int main() {
+  int x = 42;
+  return 0; // break here
+}

>From 957817bc30fa975d6b1fb54a66dc3210085e8e62 Mon Sep 17 00:00:00 2001
From: Philip DePetro <[email protected]>
Date: Wed, 4 Mar 2026 12:17:43 -0800
Subject: [PATCH 3/3] Add separate test for vfork and check exit status

---
 .../expr-with-fork/TestExprWithFork.py         | 18 +++++++++++++++++-
 .../expression/expr-with-fork/main.cpp         |  8 ++++----
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git 
a/lldb/test/API/commands/expression/expr-with-fork/TestExprWithFork.py 
b/lldb/test/API/commands/expression/expr-with-fork/TestExprWithFork.py
index 8de07a32ab7cd..80ee288ee709a 100644
--- a/lldb/test/API/commands/expression/expr-with-fork/TestExprWithFork.py
+++ b/lldb/test/API/commands/expression/expr-with-fork/TestExprWithFork.py
@@ -29,5 +29,21 @@ def test_expr_with_fork(self):
         # The fork will generate a fork stop event which ThreadPlanCallFunction
         # must handle transparently for the expression to complete.
         self.expect_expr(
-            "fork_and_return(42)", result_type="int", result_value="42"
+            "fork_and_return(42, false)", result_type="int", result_value="42"
+        )
+
+    @skipIfWindows
+    @add_test_categories(["fork"])
+    def test_expr_with_vfork(self):
+        """Test that expression evaluation succeeds when the expression calls 
vfork()."""
+        self.build()
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+
+        # Evaluate an expression that calls fork() inside a user function.
+        # The fork will generate a fork stop event which ThreadPlanCallFunction
+        # must handle transparently for the expression to complete.
+        self.expect_expr(
+            "fork_and_return(42, true)", result_type="int", result_value="42"
         )
diff --git a/lldb/test/API/commands/expression/expr-with-fork/main.cpp 
b/lldb/test/API/commands/expression/expr-with-fork/main.cpp
index 80565cf6c4420..4e210df3d7682 100644
--- a/lldb/test/API/commands/expression/expr-with-fork/main.cpp
+++ b/lldb/test/API/commands/expression/expr-with-fork/main.cpp
@@ -1,18 +1,18 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-int fork_and_return(int value) {
-  pid_t pid = fork();
+int fork_and_return(int value, bool use_vfork) {
+  pid_t pid = use_vfork ? vfork() : fork();
   if (pid == -1)
     return -1;
   if (pid == 0) {
     // child
-    _exit(0);
+    _exit(value);
   }
   // parent
   int status;
   waitpid(pid, &status, 0);
-  return value;
+  return WEXITSTATUS(status);
 }
 
 int main() {

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

Reply via email to