[Lldb-commits] [lldb] 8cd31aa - [lldb/Breakpoint] Fix condition hash after updating condition text (#181409)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Feb 13 12:08:22 PST 2026
Author: Med Ismail Bennani
Date: 2026-02-13T20:08:17Z
New Revision: 8cd31aa2c6c139b5f569b94c25462d7fcecdf7aa
URL: https://github.com/llvm/llvm-project/commit/8cd31aa2c6c139b5f569b94c25462d7fcecdf7aa
DIFF: https://github.com/llvm/llvm-project/commit/8cd31aa2c6c139b5f569b94c25462d7fcecdf7aa.diff
LOG: [lldb/Breakpoint] Fix condition hash after updating condition text (#181409)
StopCondition::SetText was computing the hash from the moved-from text
parameter instead of the stored m_text member. After std::move(text),
the source parameter becomes empty, causing the hash to always be
computed from an empty string.
This caused breakpoint condition updates to fail silently. When a user
modified a condition (e.g., from "x == y" to "x > y"), the hash remained
unchanged. Breakpoint locations use this hash to detect when conditions
need re-evaluation, so with a stale hash they would continue using
cached state for the old condition, triggering at incorrect locations.
The patch fixes this issue by computing the hash from m_text after the
move operation, ensuring it reflects the actual stored condition text.
It also adds API test that updates a breakpoint condition and verifies
the new condition is properly evaluated.
rdar://170191229
Signed-off-by: Med Ismail Bennani <ismail at bennani.ma>
Added:
lldb/test/API/functionalities/breakpoint/update_condition/Makefile
lldb/test/API/functionalities/breakpoint/update_condition/TestUpdateBreakpointCondition.py
lldb/test/API/functionalities/breakpoint/update_condition/main.c
Modified:
lldb/include/lldb/Breakpoint/StopCondition.h
Removed:
################################################################################
diff --git a/lldb/include/lldb/Breakpoint/StopCondition.h b/lldb/include/lldb/Breakpoint/StopCondition.h
index 485a615368400..9106d57435af5 100644
--- a/lldb/include/lldb/Breakpoint/StopCondition.h
+++ b/lldb/include/lldb/Breakpoint/StopCondition.h
@@ -30,7 +30,7 @@ class StopCondition {
void SetText(std::string text) {
static std::hash<std::string> hasher;
m_text = std::move(text);
- m_hash = hasher(text);
+ m_hash = hasher(m_text);
}
size_t GetHash() const { return m_hash; }
diff --git a/lldb/test/API/functionalities/breakpoint/update_condition/Makefile b/lldb/test/API/functionalities/breakpoint/update_condition/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/update_condition/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/breakpoint/update_condition/TestUpdateBreakpointCondition.py b/lldb/test/API/functionalities/breakpoint/update_condition/TestUpdateBreakpointCondition.py
new file mode 100644
index 0000000000000..ae929fc4d9f5a
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/update_condition/TestUpdateBreakpointCondition.py
@@ -0,0 +1,126 @@
+"""
+Test that updating a breakpoint condition correctly invalidates cached state.
+
+This test verifies that when a breakpoint condition is changed, the new condition
+is properly evaluated. Previously, due to a bug in StopCondition::SetText where
+the hash was computed from a moved-from string, updating conditions could fail
+to invalidate cached condition state at breakpoint locations.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class UpdateBreakpointConditionTestCase(TestBase):
+ def setUp(self):
+ TestBase.setUp(self)
+ self.source = "main.c"
+
+ @add_test_categories(["pyapi"])
+ def test_update_condition_python_api(self):
+ """Test that updating a breakpoint condition works correctly using Python API."""
+ self.build()
+ target, process, thread, breakpoint = lldbutil.run_to_source_breakpoint(
+ self, "Set breakpoint here", lldb.SBFileSpec(self.source)
+ )
+
+ # Set initial condition: x == y.
+ breakpoint.SetCondition("x == y")
+ self.assertEqual(breakpoint.GetCondition(), "x == y")
+
+ # Need to continue since we're already stopped, but the condition wasn't set initially.
+ # First hit should be at foo(5, 5) where x == y.
+ process.Continue()
+ thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+ self.assertTrue(thread.IsValid(), "Should stop at first x == y condition")
+
+ frame = thread.GetFrameAtIndex(0)
+ x_val = frame.FindVariable("x")
+ y_val = frame.FindVariable("y")
+ self.assertEqual(x_val.GetValueAsSigned(), 5, "x should be 5")
+ self.assertEqual(y_val.GetValueAsSigned(), 5, "y should be 5")
+ self.assertEqual(breakpoint.GetHitCount(), 2)
+
+ # Continue to second hit with x == y.
+ process.Continue()
+ thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+ self.assertTrue(thread.IsValid(), "Should stop at second x == y condition")
+
+ frame = thread.GetFrameAtIndex(0)
+ x_val = frame.FindVariable("x")
+ y_val = frame.FindVariable("y")
+ self.assertEqual(x_val.GetValueAsSigned(), 6, "x should be 6")
+ self.assertEqual(y_val.GetValueAsSigned(), 6, "y should be 6")
+ self.assertEqual(breakpoint.GetHitCount(), 3)
+
+ # Now update the condition to x > y.
+ # This tests the fix for the bug where the hash wasn't updated correctly.
+ breakpoint.SetCondition("x > y")
+ self.assertEqual(breakpoint.GetCondition(), "x > y")
+
+ # Continue - should now hit at foo(3, 1) where x > y (3 > 1).
+ # Without the fix, it would incorrectly hit at foo(7, 7) due to stale condition hash.
+ process.Continue()
+ thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+ self.assertTrue(thread.IsValid(), "Should stop at x > y condition")
+
+ frame = thread.GetFrameAtIndex(0)
+ x_val = frame.FindVariable("x")
+ y_val = frame.FindVariable("y")
+ self.assertEqual(x_val.GetValueAsSigned(), 3, "x should be 3")
+ self.assertEqual(y_val.GetValueAsSigned(), 1, "y should be 1")
+ self.assertTrue(
+ x_val.GetValueAsSigned() > y_val.GetValueAsSigned(),
+ "Condition x > y should be true",
+ )
+ self.assertEqual(breakpoint.GetHitCount(), 4)
+
+ def test_update_condition_command(self):
+ """Test that updating a breakpoint condition works correctly using breakpoint modify."""
+ self.build()
+ target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
+ self, "Set breakpoint here", lldb.SBFileSpec(self.source)
+ )
+
+ # Set initial condition: x == y.
+ self.runCmd("breakpoint modify -c 'x == y' 1")
+ self.expect(
+ "breakpoint list",
+ substrs=["Condition: x == y"],
+ )
+
+ # Continue to first hit at foo(5, 5).
+ self.runCmd("continue")
+ self.expect("process status", PROCESS_STOPPED, patterns=["Process .* stopped"])
+ self.expect(
+ "frame variable x y",
+ substrs=["x = 5", "y = 5"],
+ )
+
+ # Continue to second hit.
+ self.runCmd("continue")
+ self.expect("process status", PROCESS_STOPPED, patterns=["Process .* stopped"])
+ self.expect(
+ "frame variable x y",
+ substrs=["x = 6", "y = 6"],
+ )
+
+ # Update condition to x > y.
+ self.runCmd("breakpoint modify -c 'x > y' 1")
+ self.expect(
+ "breakpoint list",
+ substrs=["Condition: x > y"],
+ )
+
+ # Continue - should hit at foo(3, 1) where x > y.
+ self.runCmd("continue")
+ self.expect("process status", PROCESS_STOPPED, patterns=["Process .* stopped"])
+ self.expect(
+ "frame variable x y",
+ substrs=["x = 3", "y = 1"],
+ )
+
+ # Verify x > y is actually true.
+ self.expect("expr x > y", substrs=["true"])
diff --git a/lldb/test/API/functionalities/breakpoint/update_condition/main.c b/lldb/test/API/functionalities/breakpoint/update_condition/main.c
new file mode 100644
index 0000000000000..7900f9fff8bb1
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/update_condition/main.c
@@ -0,0 +1,16 @@
+int foo(int x, int y) {
+ return x - y + 5; // Set breakpoint here.
+}
+
+int main() {
+ foo(1, 4);
+ foo(5, 1);
+ foo(5, 5);
+ foo(3, -1);
+ foo(6, 6);
+ foo(7, 7);
+ foo(1, 3);
+ foo(3, 1);
+
+ return 0;
+}
More information about the lldb-commits
mailing list