| """ |
| 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"]) |