Fix crash if breakpoint commands contain detach or kill
If breakpoint commands contain detach or kill, then gdb tries to access
freed memory:
(gdb) b main
Breakpoint 1 at 0x111d: file main.c, line 21.
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>detach
>end
(gdb) run
Starting program: /home/src/lappy/binutils-gdb.git/gdb/testsuite/gdb.base/main
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1".
main () at main.c:21
21 return 0;
[Inferior 1 (process 241852) detached]
=================================================================
==241817==ERROR: AddressSanitizer: heap-use-after-free on address 0x7b7a3de0b760 at pc 0x55fcb92613fe bp 0x7ffec2d524f0 sp 0x7ffec2d524e0
READ of size 8 at 0x7b7a3de0b760 thread T0
#0 0x55fcb92613fd in bpstat_do_actions_1 ../../gdb/breakpoint.c:4898
#1 0x55fcb92617da in bpstat_do_actions() ../../gdb/breakpoint.c:5012
#2 0x55fcba3180e7 in inferior_event_handler(inferior_event_type) ../../gdb/inf-loop.c:71
#3 0x55fcba3ba1e1 in fetch_inferior_event() ../../gdb/infrun.c:4769
0x7b7a3de0b760 is located 0 bytes inside of 56-byte region [0x7b7a3de0b760,0x7b7a3de0b798)
freed by thread T0 here:
#0 0x7f1a43522a2d in operator delete(void*, unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:155
#1 0x55fcb925d5cd in bpstat_clear(bpstat**) ../../gdb/breakpoint.c:4646
#2 0x55fcbb69ea6a in clear_thread_inferior_resources ../../gdb/thread.c:185
#3 0x55fcbb69f4cb in set_thread_exited(thread_info*, std::optional<unsigned long>, bool) ../../gdb/thread.c:244
#4 0x55fcba368d64 in operator() ../../gdb/inferior.c:269
#5 0x55fcba375e2b in clear_and_dispose<inferior::clear_thread_list()::<lambda(thread_info*)> > ../../gdb/../gdbsupport/intrusive_list.h:529
#6 0x55fcba368f19 in inferior::clear_thread_list() ../../gdb/inferior.c:265
#7 0x55fcba3694ba in exit_inferior(inferior*) ../../gdb/inferior.c:322
#8 0x55fcba369e35 in detach_inferior(inferior*) ../../gdb/inferior.c:358
#9 0x55fcba319d9f in inf_ptrace_target::detach_success(inferior*) ../../gdb/inf-ptrace.c:214
#10 0x55fcba56a2f6 in linux_nat_target::detach(inferior*, int) ../../gdb/linux-nat.c:1582
#11 0x55fcba62121c in thread_db_target::detach(inferior*, int) ../../gdb/linux-thread-db.c:1381
#12 0x55fcbb5ca49e in target_detach(inferior*, int) ../../gdb/target.c:2557
#13 0x55fcba356ba4 in detach_command(char const*, int) ../../gdb/infcmd.c:2894
#14 0x55fcb9597eea in do_simple_func ../../gdb/cli/cli-decode.c:94
#15 0x55fcb95b10b5 in cmd_func(cmd_list_element*, char const*, int) ../../gdb/cli/cli-decode.c:2831
#16 0x55fcbb6f5282 in execute_command(char const*, int) ../../gdb/top.c:563
#17 0x55fcb95eedb9 in execute_control_command_1 ../../gdb/cli/cli-script.c:526
#18 0x55fcb95f04dd in execute_control_command(command_line*, int) ../../gdb/cli/cli-script.c:702
#19 0x55fcb9261175 in bpstat_do_actions_1 ../../gdb/breakpoint.c:4940
#20 0x55fcb92617da in bpstat_do_actions() ../../gdb/breakpoint.c:5012
#21 0x55fcba3180e7 in inferior_event_handler(inferior_event_type) ../../gdb/inf-loop.c:71
#22 0x55fcba3ba1e1 in fetch_inferior_event() ../../gdb/infrun.c:4769
previously allocated by thread T0 here:
#0 0x7f1a435218cd in operator new(unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:86
#1 0x55fcb927061f in build_bpstat_chain(address_space const*, unsigned long, target_waitstatus const&) ../../gdb/breakpoint.c:5880
#2 0x55fcba3d63b6 in handle_signal_stop ../../gdb/infrun.c:7083
#3 0x55fcba3d01c7 in handle_inferior_event ../../gdb/infrun.c:6574
#4 0x55fcba3b9918 in fetch_inferior_event() ../../gdb/infrun.c:4713
This checks after executing commands of each breakpoint if the bpstat
was deleted already, and stops any further processing immediately.
Now the result looks like this:
(gdb) b main
Breakpoint 1 at 0x111d: file main.c, line 21.
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>detach
>end
(gdb) run
Starting program: /home/src/lappy/binutils-gdb.git/gdb/testsuite/gdb.base/main
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/../lib/libthread_db.so.1".
main () at main.c:21
21 return 0;
[Inferior 1 (process 242940) detached]
(gdb)
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=14354 Approved-By: Andrew Burgess <aburgess@redhat.com>