[Lldb-commits] [lldb] [lldb] Fix crash after second run when set a previous watchpoint. (PR #136682)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Apr 24 07:34:13 PDT 2025
https://github.com/hapeeeeee updated https://github.com/llvm/llvm-project/pull/136682
>From 563cbddfe9b7da394c818a03e05924c0f7d39d5f Mon Sep 17 00:00:00 2001
From: hapeeeeee <623151737 at qq.com>
Date: Tue, 22 Apr 2025 11:34:38 +0800
Subject: [PATCH 1/3] [lldb] Fix crash after second run when set a previous
watchpoint.
---
lldb/source/Breakpoint/Watchpoint.cpp | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp
index 2df848aaa0576..0fcc9b90c0ab5 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -409,6 +409,15 @@ bool Watchpoint::IsDisabledDuringEphemeralMode() {
}
void Watchpoint::SetEnabled(bool enabled, bool notify) {
+ // Whenever setting the enabled state of a watchpoint, we need to ensure
+ // that `m_new_value_sp` exists to avoid crash when reading old_data later.
+ // See https://github.com/llvm/llvm-project/issues/135590.
+ if (!m_new_value_sp) {
+ ExecutionContext exe_ctx;
+ m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
+ CaptureWatchedValue(exe_ctx);
+ }
+
if (!enabled) {
if (m_is_ephemeral)
++m_disabled_count;
>From 980c9bc97011fa4fbce4f67688c3539f3d518a42 Mon Sep 17 00:00:00 2001
From: hapeeeeee <623151737 at qq.com>
Date: Wed, 23 Apr 2025 21:33:32 +0800
Subject: [PATCH 2/3] add testcase
---
.../Makefile | 3 +
.../TestReuseWatchpointAfterReExecProcess.py | 71 +++++++++++++++++++
.../main.c | 5 ++
3 files changed, 79 insertions(+)
create mode 100644 lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/Makefile
create mode 100644 lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/TestReuseWatchpointAfterReExecProcess.py
create mode 100644 lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/main.c
diff --git a/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/Makefile b/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/TestReuseWatchpointAfterReExecProcess.py b/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/TestReuseWatchpointAfterReExecProcess.py
new file mode 100644
index 0000000000000..d4b4afd538cde
--- /dev/null
+++ b/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/TestReuseWatchpointAfterReExecProcess.py
@@ -0,0 +1,71 @@
+"""
+Set a watchpoint on a variable, then kill the process and restart it with the same watchpoint.
+Check whether LLDB crashes due to a dangling pointer.
+"""
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestReuseWatchpointAfterReExecProcess(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def continue_and_report_stop_reason(self, process, iter_str):
+ process.Continue()
+ self.assertIn(
+ process.GetState(), [lldb.eStateStopped, lldb.eStateExited], iter_str
+ )
+ thread = process.GetSelectedThread()
+ return thread.GetStopReason()
+
+ # debugserver only gained the ability to watch larger regions
+ # with this patch.
+ def test_reuse_watchpoint_after_re_exec_process(self):
+ """Test watchpoint that covers a large region of memory."""
+ self.build()
+ self.main_source_file = lldb.SBFileSpec("main.c")
+ (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+ self, "break here", self.main_source_file
+ )
+
+ frame = thread.GetFrameAtIndex(0)
+ var_wp = (
+ frame.locals["var"][0]
+ .Watch(True, False, True)
+ )
+ self.assertTrue(var_wp.IsValid())
+
+ # Kill the process and restart it with the same watchpoint.
+ process.Kill()
+ process = target.LaunchSimple(None, None, os.getcwd())
+ bkpt = target.BreakpointCreateBySourceRegex(
+ "break here", self.main_source_file, None
+ )
+
+ threads = lldbutil.get_threads_stopped_at_breakpoint(process, bkpt)
+ thread = threads[0]
+ frame = thread.GetFrameAtIndex(0)
+
+ var_reused_wp = (
+ frame.locals["var"][0]
+ .Watch(True, False, True)
+ )
+
+ self.assertTrue(var_reused_wp.IsValid())
+ process.Continue()
+ reason = self.continue_and_report_stop_reason(process, "continue to reused var wp")
+ self.assertEqual(reason, lldb.eStopReasonWatchpoint)
+
+ stop_reason_watchpoint_id = (
+ process.GetSelectedThread().GetStopReasonDataAtIndex(0)
+ )
+ self.assertEqual(stop_reason_watchpoint_id, var_reused_wp.GetID())
+
+ # Check that the process exited, instead of crashing
+ process.Continue()
+ self.assertState(process.GetState(), lldb.eStateExited)
+
+
\ No newline at end of file
diff --git a/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/main.c b/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/main.c
new file mode 100644
index 0000000000000..8cf70d8b06d69
--- /dev/null
+++ b/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/main.c
@@ -0,0 +1,5 @@
+int main() {
+ int var;
+ var = 2; // break here
+ return 0;
+}
\ No newline at end of file
>From 06736af2e311c693edad289c3a6f822d2de9d196 Mon Sep 17 00:00:00 2001
From: hapeeeeee <623151737 at qq.com>
Date: Thu, 24 Apr 2025 22:33:23 +0800
Subject: [PATCH 3/3] Add Shell Test
---
.../Makefile | 3 -
.../TestReuseWatchpointAfterReExecProcess.py | 71 -------------------
.../main.c | 5 --
.../ReuseWatchpointAfterReExecProcess.test | 21 ++++++
4 files changed, 21 insertions(+), 79 deletions(-)
delete mode 100644 lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/Makefile
delete mode 100644 lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/TestReuseWatchpointAfterReExecProcess.py
delete mode 100644 lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/main.c
create mode 100644 lldb/test/Shell/Watchpoint/ReuseWatchpointAfterReExecProcess.test
diff --git a/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/Makefile b/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/Makefile
deleted file mode 100644
index 10495940055b6..0000000000000
--- a/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-C_SOURCES := main.c
-
-include Makefile.rules
diff --git a/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/TestReuseWatchpointAfterReExecProcess.py b/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/TestReuseWatchpointAfterReExecProcess.py
deleted file mode 100644
index d4b4afd538cde..0000000000000
--- a/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/TestReuseWatchpointAfterReExecProcess.py
+++ /dev/null
@@ -1,71 +0,0 @@
-"""
-Set a watchpoint on a variable, then kill the process and restart it with the same watchpoint.
-Check whether LLDB crashes due to a dangling pointer.
-"""
-
-import os
-import lldb
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class TestReuseWatchpointAfterReExecProcess(TestBase):
- NO_DEBUG_INFO_TESTCASE = True
-
- def continue_and_report_stop_reason(self, process, iter_str):
- process.Continue()
- self.assertIn(
- process.GetState(), [lldb.eStateStopped, lldb.eStateExited], iter_str
- )
- thread = process.GetSelectedThread()
- return thread.GetStopReason()
-
- # debugserver only gained the ability to watch larger regions
- # with this patch.
- def test_reuse_watchpoint_after_re_exec_process(self):
- """Test watchpoint that covers a large region of memory."""
- self.build()
- self.main_source_file = lldb.SBFileSpec("main.c")
- (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
- self, "break here", self.main_source_file
- )
-
- frame = thread.GetFrameAtIndex(0)
- var_wp = (
- frame.locals["var"][0]
- .Watch(True, False, True)
- )
- self.assertTrue(var_wp.IsValid())
-
- # Kill the process and restart it with the same watchpoint.
- process.Kill()
- process = target.LaunchSimple(None, None, os.getcwd())
- bkpt = target.BreakpointCreateBySourceRegex(
- "break here", self.main_source_file, None
- )
-
- threads = lldbutil.get_threads_stopped_at_breakpoint(process, bkpt)
- thread = threads[0]
- frame = thread.GetFrameAtIndex(0)
-
- var_reused_wp = (
- frame.locals["var"][0]
- .Watch(True, False, True)
- )
-
- self.assertTrue(var_reused_wp.IsValid())
- process.Continue()
- reason = self.continue_and_report_stop_reason(process, "continue to reused var wp")
- self.assertEqual(reason, lldb.eStopReasonWatchpoint)
-
- stop_reason_watchpoint_id = (
- process.GetSelectedThread().GetStopReasonDataAtIndex(0)
- )
- self.assertEqual(stop_reason_watchpoint_id, var_reused_wp.GetID())
-
- # Check that the process exited, instead of crashing
- process.Continue()
- self.assertState(process.GetState(), lldb.eStateExited)
-
-
\ No newline at end of file
diff --git a/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/main.c b/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/main.c
deleted file mode 100644
index 8cf70d8b06d69..0000000000000
--- a/lldb/test/API/functionalities/watchpoint/reuse-watchpoint-after-re-exec-process/main.c
+++ /dev/null
@@ -1,5 +0,0 @@
-int main() {
- int var;
- var = 2; // break here
- return 0;
-}
\ No newline at end of file
diff --git a/lldb/test/Shell/Watchpoint/ReuseWatchpointAfterReExecProcess.test b/lldb/test/Shell/Watchpoint/ReuseWatchpointAfterReExecProcess.test
new file mode 100644
index 0000000000000..6af27856e6ee6
--- /dev/null
+++ b/lldb/test/Shell/Watchpoint/ReuseWatchpointAfterReExecProcess.test
@@ -0,0 +1,21 @@
+# RUN: %clangxx_host %p/Inputs/languages.cpp -g -o %t.out
+# RUN: %lldb -b -o 'settings set interpreter.stop-command-source-on-error false' -s %s %t.out 2>&1 | FileCheck %s
+
+b main
+run
+# CHECK: stopped
+# CHECK-NEXT: stop reason = breakpoint
+
+watchpoint set variable val
+# CHECK: Watchpoint created:
+
+kill
+run
+# CHECK: stopped
+# CHECK-NEXT: stop reason = breakpoint
+
+watchpoint set variable val
+# CHECK: Watchpoint created:
+
+continue
+# CHECK: Watchpoint 1 hit:
\ No newline at end of file
More information about the lldb-commits
mailing list