Skip to content

Commit ec48d15

Browse files
authored
Fix a bug in the breakpoint ID verifier in CommandObjectBreakpoint. (#145994)
It was assuming that for any location M.N, N was always less than the number of breakpoint locations. But if you rebuild the target and rerun multiple times, when the section backing one of the locations is no longer valid, we remove the location, but we don't reuse the ID. So you can have a breakpoint that only has location 1.3. The num_locations check would say that was an invalid location.
1 parent c3811c8 commit ec48d15

File tree

6 files changed

+63
-2
lines changed

6 files changed

+63
-2
lines changed

lldb/source/Commands/CommandObjectBreakpoint.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2485,8 +2485,9 @@ void CommandObjectMultiwordBreakpoint::VerifyIDs(
24852485
Breakpoint *breakpoint =
24862486
target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
24872487
if (breakpoint != nullptr) {
2488-
const size_t num_locations = breakpoint->GetNumLocations();
2489-
if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) {
2488+
lldb::break_id_t cur_loc_id = cur_bp_id.GetLocationID();
2489+
// GetLocationID returns 0 when the location isn't specified.
2490+
if (cur_loc_id != 0 && !breakpoint->FindLocationByID(cur_loc_id)) {
24902491
StreamString id_str;
24912492
BreakpointID::GetCanonicalReference(
24922493
&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
When a rebuild causes a location to be removed, make sure
3+
we still handle the remaining locations correctly.
4+
"""
5+
6+
7+
import lldb
8+
import lldbsuite.test.lldbutil as lldbutil
9+
from lldbsuite.test.lldbtest import *
10+
import os
11+
12+
13+
class TestLocationsAfterRebuild(TestBase):
14+
# If your test case doesn't stress debug info, then
15+
# set this to true. That way it won't be run once for
16+
# each debug info format.
17+
NO_DEBUG_INFO_TESTCASE = True
18+
19+
def test_remaining_location_spec(self):
20+
"""If we rebuild a couple of times some of the old locations
21+
get removed. Make sure the command-line breakpoint id
22+
validator still works correctly."""
23+
self.build(dictionary={"C_SOURCES": "main.c", "EXE": "a.out"})
24+
25+
path_to_exe = self.getBuildArtifact()
26+
27+
(target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(self, "main")
28+
29+
# Let the process continue to exit:
30+
process.Continue()
31+
self.assertEqual(process.GetState(), lldb.eStateExited, "Ran to completion")
32+
os.remove(path_to_exe)
33+
34+
# We have to rebuild twice with changed sources to get
35+
# us to remove the first set of locations:
36+
self.build(dictionary={"C_SOURCES": "second_main.c", "EXE": "a.out"})
37+
38+
(target, process, thread, bkpt) = lldbutil.run_to_breakpoint_do_run(
39+
self, target, bkpt
40+
)
41+
42+
# Let the process continue to exit:
43+
process.Continue()
44+
self.assertEqual(process.GetState(), lldb.eStateExited, "Ran to completion")
45+
46+
os.remove(path_to_exe)
47+
48+
self.build(dictionary={"C_SOURCES": "third_main.c", "EXE": "a.out"})
49+
50+
(target, process, thread, bkpt) = lldbutil.run_to_breakpoint_do_run(
51+
self, target, bkpt
52+
)
53+
54+
bkpt_id = bkpt.GetID()
55+
loc_string = f"{bkpt_id}.3"
56+
self.runCmd(f"break disable {loc_string}")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int main() { return 1111; }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int main() { return 22222; }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int main() { return 33333; }

0 commit comments

Comments
 (0)