]> git.feebdaed.xyz Git - 0xmirror/binutils-gdb.git/commit
Fix crash if breakpoint commands contain detach or kill
authorHannes Domani <ssbssa@yahoo.de>
Mon, 22 Dec 2025 11:06:43 +0000 (12:06 +0100)
committerHannes Domani <ssbssa@yahoo.de>
Mon, 22 Dec 2025 11:08:49 +0000 (12:08 +0100)
commit39c9aaea70056290e48da6e430b9d1328888c4c4
treeab123833867b97190fbe1d1c78e374ae15415b29
parentc2db59a7a276a77eef1e70f545fb4344cc7696a0
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>
gdb/breakpoint.c
gdb/testsuite/gdb.base/detach-in-breakpoint-commands.exp [new file with mode: 0644]