From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 2D17B3857023 for ; Wed, 10 May 2023 09:12:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2D17B3857023 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1683709957; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=fLuWX57yPNL4mdAiL6HeecBCcRS4hfYBeWxwpGe39Lw=; b=iQofd8tYSilaXG2nEdEqeqiSwKdwEXXwAha0Buwj5i7WlaXkEI/ADpO3+kl2rM2WzGu1Ee mGFiKzEwNQErwB98irWdtIrv5f7IBDPxqd5cppNOE1AdYE3Z0uTZ1ptoSggpzefF8+n8Jk +F7v+1p+MSOP4v/vXXL/qssLUPozu7Y= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-42-WuUS_ds6P0qKAeffA1HfKQ-1; Wed, 10 May 2023 05:12:36 -0400 X-MC-Unique: WuUS_ds6P0qKAeffA1HfKQ-1 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-306489b7585so2386699f8f.3 for ; Wed, 10 May 2023 02:12:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683709955; x=1686301955; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=fLuWX57yPNL4mdAiL6HeecBCcRS4hfYBeWxwpGe39Lw=; b=iFRqWEsIu/wr8rH7cQ/HP/zP9DgGZ/KfYSsUq31Mhya6nqNUYzDuaMYl5pjAHMnFqU m5smc5TVxl++CtljbeNDHvGiSUcQVA7MM8lQvxyMKR4s5hmtKzsPEAuFeGex+cKErNSV QyiKaNsYK5iEctoLDmHgqRop107MJgrFosUCe3FgvFQN5tvpWzwh9eTrhgD6iLLzBpu+ OUpTKGmuYwgofEvrZyRhd0F8j1uT4IZIGozA8E3Z6OrSoyQXwPsFqEushX/cnrjnLcFV o1J47T4tShIjHVlFY82xAaRd7XGGUO4f8oSXwR+59i8q1QyCaq9uExvXCmoyPYqlad1c zK5A== X-Gm-Message-State: AC+VfDyb/Ys8kq+wytP5JW2437Z6lYGKC/XVCYjBv8W4jPVeESdlh7Nf wFK4PPiebvInKOoDdO2XBI2evqtrrkq5S4GoEyeY5SmoSVN+i1BU3svO0oufS5OB2SZ1BfJS2Nf HKADpgSaXVCYUUfwbdMubIe1cvtubuL1/dj1g8ktS6hjq/170fBltUe5d9eIG/20fMLZD/2G/l1 VSLMu8Kg== X-Received: by 2002:adf:cc89:0:b0:305:e8db:37df with SMTP id p9-20020adfcc89000000b00305e8db37dfmr11928068wrj.22.1683709955265; Wed, 10 May 2023 02:12:35 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6VBVNJPwEK/cvvH3aUzHEwN0TO0xulOaW3SnJkSvM4yEOtjoJehIOjkF+PUApfW/wPT0Ctsg== X-Received: by 2002:adf:cc89:0:b0:305:e8db:37df with SMTP id p9-20020adfcc89000000b00305e8db37dfmr11928043wrj.22.1683709954733; Wed, 10 May 2023 02:12:34 -0700 (PDT) Received: from localhost (11.72.115.87.dyn.plus.net. [87.115.72.11]) by smtp.gmail.com with ESMTPSA id i6-20020adfdec6000000b002c70ce264bfsm16688860wrn.76.2023.05.10.02.12.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 May 2023 02:12:34 -0700 (PDT) From: Andrew Burgess To: Simon Marchi via Gdb-patches , gdb-patches@sourceware.org Cc: Simon Marchi Subject: Re: [PATCH] gdb: fix use-after-free in check_longjmp_breakpoint_for_call_dummy In-Reply-To: <20230508145913.29359-1-simon.marchi@efficios.com> References: <20230508145913.29359-1-simon.marchi@efficios.com> Date: Wed, 10 May 2023 10:12:33 +0100 Message-ID: <87h6sk7doe.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_LOTSOFHASH,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE,WEIRD_PORT autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Simon Marchi via Gdb-patches writes: > Commit 7a8de0c33019 ("Remove ALL_BREAKPOINTS_SAFE") introduced a > use-after-free in the breakpoints iterations (see below for full ASan > report). This makes gdb.base/stale-infcall.exp fail when GDB is build > with ASan. > > check_longjmp_breakpoint_for_call_dummy iterates on all breakpoints, > possibly deleting the current breakpoint as well as related breakpoints. > The problem arises when a breakpoint in the B->related_breakpoint chain > is also B->next. In that case, deleting that related breakpoint frees > the breakpoint that all_breakpoints_safe has saved. > > The old code worked around that by manually changing B_TMP, which was > the next breakpoint saved by the "safe iterator": > > while (b->related_breakpoint != b) > { > if (b_tmp == b->related_breakpoint) > b_tmp = b->related_breakpoint->next; > delete_breakpoint (b->related_breakpoint); > } > > (Note that this seemed to assume that b->related_breakpoint->next was > the same as b->next->next, not sure this is guaranteed.) > > The new code kept the B_TMP variable, but it's not useful in that > context. We can't go change the next breakpoint as saved by the safe > iterator, like we did before. I suggest fixing that by saving the > breakpoints to delete in a map and deleting them all at the end. > > Here's the full ASan report: > > (gdb) PASS: gdb.base/stale-infcall.exp: continue to breakpoint: break-run1 > print infcall () > ================================================================= > ==47472==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000034980 at pc 0x563f7012c7bc bp 0x7ffdf3804d70 sp 0x7ffdf3804d60 > READ of size 8 at 0x611000034980 thread T0 > #0 0x563f7012c7bb in next_iterator::operator++() /home/smarchi/src/binutils-gdb/gdb/../gdbsupport/next-iterator.h:66 > #1 0x563f702ce8c0 in basic_safe_iterator >::operator++() /home/smarchi/src/binutils-gdb/gdb/../gdbsupport/safe-iterator.h:84 > #2 0x563f7021522a in check_longjmp_breakpoint_for_call_dummy(thread_info*) /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:7611 > #3 0x563f714567b1 in process_event_stop_test /home/smarchi/src/binutils-gdb/gdb/infrun.c:6881 > #4 0x563f71454e07 in handle_signal_stop /home/smarchi/src/binutils-gdb/gdb/infrun.c:6769 > #5 0x563f7144b680 in handle_inferior_event /home/smarchi/src/binutils-gdb/gdb/infrun.c:6023 > #6 0x563f71436165 in fetch_inferior_event() /home/smarchi/src/binutils-gdb/gdb/infrun.c:4387 > #7 0x563f7136ff51 in inferior_event_handler(inferior_event_type) /home/smarchi/src/binutils-gdb/gdb/inf-loop.c:42 > #8 0x563f7168038d in handle_target_event /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:4219 > #9 0x563f72fccb6d in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:573 > #10 0x563f72fcd503 in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:694 > #11 0x563f72fcaf2b in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:217 > #12 0x563f7262b9bb in wait_sync_command_done() /home/smarchi/src/binutils-gdb/gdb/top.c:426 > #13 0x563f7137a7c3 in run_inferior_call /home/smarchi/src/binutils-gdb/gdb/infcall.c:650 > #14 0x563f71381295 in call_function_by_hand_dummy(value*, type*, gdb::array_view, void (*)(void*, int), void*) /home/smarchi/src/binutils-gdb/gdb/infcall.c:1332 > #15 0x563f7137c0e2 in call_function_by_hand(value*, type*, gdb::array_view) /home/smarchi/src/binutils-gdb/gdb/infcall.c:780 > #16 0x563f70fe5960 in evaluate_subexp_do_call(expression*, noside, value*, gdb::array_view, char const*, type*) /home/smarchi/src/binutils-gdb/gdb/eval.c:649 > #17 0x563f70fe6617 in expr::operation::evaluate_funcall(type*, expression*, noside, char const*, std::__debug::vector >, std::allocator > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:677 > #18 0x563f6fd19668 in expr::operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector >, std::allocator > > > const&) /home/smarchi/src/binutils-gdb/gdb/expression.h:136 > #19 0x563f70fe6bba in expr::var_value_operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector >, std::allocator > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:689 > #20 0x563f704b71dc in expr::funcall_operation::evaluate(type*, expression*, noside) /home/smarchi/src/binutils-gdb/gdb/expop.h:2219 > #21 0x563f70fe0f02 in expression::evaluate(type*, noside) /home/smarchi/src/binutils-gdb/gdb/eval.c:110 > #22 0x563f71b1373e in process_print_command_args /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1319 > #23 0x563f71b1391b in print_command_1 /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1332 > #24 0x563f71b147ec in print_command /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1465 > #25 0x563f706029b8 in do_simple_func /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:95 > #26 0x563f7061972a in cmd_func(cmd_list_element*, char const*, int) /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:2735 > #27 0x563f7262d0ef in execute_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/top.c:572 > #28 0x563f7100ed9c in command_handler(char const*) /home/smarchi/src/binutils-gdb/gdb/event-top.c:543 > #29 0x563f7101014b in command_line_handler(std::unique_ptr >&&) /home/smarchi/src/binutils-gdb/gdb/event-top.c:779 > #30 0x563f72777942 in tui_command_line_handler /home/smarchi/src/binutils-gdb/gdb/tui/tui-interp.c:104 > #31 0x563f7100d059 in gdb_rl_callback_handler /home/smarchi/src/binutils-gdb/gdb/event-top.c:250 > #32 0x7f5a80418246 in rl_callback_read_char (/usr/lib/libreadline.so.8+0x3b246) (BuildId: 092e91fc4361b0ef94561e3ae03a75f69398acbb) > #33 0x563f7100ca06 in gdb_rl_callback_read_char_wrapper_noexcept /home/smarchi/src/binutils-gdb/gdb/event-top.c:192 > #34 0x563f7100cc5e in gdb_rl_callback_read_char_wrapper /home/smarchi/src/binutils-gdb/gdb/event-top.c:225 > #35 0x563f728c70db in stdin_event_handler /home/smarchi/src/binutils-gdb/gdb/ui.c:155 > #36 0x563f72fccb6d in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:573 > #37 0x563f72fcd503 in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:694 > #38 0x563f72fcb15c in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:264 > #39 0x563f7177ec1c in start_event_loop /home/smarchi/src/binutils-gdb/gdb/main.c:412 > #40 0x563f7177f12e in captured_command_loop /home/smarchi/src/binutils-gdb/gdb/main.c:476 > #41 0x563f717846e4 in captured_main /home/smarchi/src/binutils-gdb/gdb/main.c:1320 > #42 0x563f71784821 in gdb_main(captured_main_args*) /home/smarchi/src/binutils-gdb/gdb/main.c:1339 > #43 0x563f6fcedfbd in main /home/smarchi/src/binutils-gdb/gdb/gdb.c:32 > #44 0x7f5a7e43984f (/usr/lib/libc.so.6+0x2384f) (BuildId: 2f005a79cd1a8e385972f5a102f16adba414d75e) > #45 0x7f5a7e439909 in __libc_start_main (/usr/lib/libc.so.6+0x23909) (BuildId: 2f005a79cd1a8e385972f5a102f16adba414d75e) > #46 0x563f6fcedd84 in _start (/home/smarchi/build/binutils-gdb/gdb/gdb+0xafb0d84) (BuildId: 50bd32e6e9d5e84543e9897b8faca34858ca3995) > > 0x611000034980 is located 0 bytes inside of 208-byte region [0x611000034980,0x611000034a50) > freed by thread T0 here: > #0 0x7f5a7fce312a in operator delete(void*, unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:164 > #1 0x563f702bd1fa in momentary_breakpoint::~momentary_breakpoint() /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:304 > #2 0x563f702771c5 in delete_breakpoint(breakpoint*) /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:12404 > #3 0x563f702150a7 in check_longjmp_breakpoint_for_call_dummy(thread_info*) /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:7673 > #4 0x563f714567b1 in process_event_stop_test /home/smarchi/src/binutils-gdb/gdb/infrun.c:6881 > #5 0x563f71454e07 in handle_signal_stop /home/smarchi/src/binutils-gdb/gdb/infrun.c:6769 > #6 0x563f7144b680 in handle_inferior_event /home/smarchi/src/binutils-gdb/gdb/infrun.c:6023 > #7 0x563f71436165 in fetch_inferior_event() /home/smarchi/src/binutils-gdb/gdb/infrun.c:4387 > #8 0x563f7136ff51 in inferior_event_handler(inferior_event_type) /home/smarchi/src/binutils-gdb/gdb/inf-loop.c:42 > #9 0x563f7168038d in handle_target_event /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:4219 > #10 0x563f72fccb6d in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:573 > #11 0x563f72fcd503 in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:694 > #12 0x563f72fcaf2b in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:217 > #13 0x563f7262b9bb in wait_sync_command_done() /home/smarchi/src/binutils-gdb/gdb/top.c:426 > #14 0x563f7137a7c3 in run_inferior_call /home/smarchi/src/binutils-gdb/gdb/infcall.c:650 > #15 0x563f71381295 in call_function_by_hand_dummy(value*, type*, gdb::array_view, void (*)(void*, int), void*) /home/smarchi/src/binutils-gdb/gdb/infcall.c:1332 > #16 0x563f7137c0e2 in call_function_by_hand(value*, type*, gdb::array_view) /home/smarchi/src/binutils-gdb/gdb/infcall.c:780 > #17 0x563f70fe5960 in evaluate_subexp_do_call(expression*, noside, value*, gdb::array_view, char const*, type*) /home/smarchi/src/binutils-gdb/gdb/eval.c:649 > #18 0x563f70fe6617 in expr::operation::evaluate_funcall(type*, expression*, noside, char const*, std::__debug::vector >, std::allocator > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:677 > #19 0x563f6fd19668 in expr::operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector >, std::allocator > > > const&) /home/smarchi/src/binutils-gdb/gdb/expression.h:136 > #20 0x563f70fe6bba in expr::var_value_operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector >, std::allocator > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:689 > #21 0x563f704b71dc in expr::funcall_operation::evaluate(type*, expression*, noside) /home/smarchi/src/binutils-gdb/gdb/expop.h:2219 > #22 0x563f70fe0f02 in expression::evaluate(type*, noside) /home/smarchi/src/binutils-gdb/gdb/eval.c:110 > #23 0x563f71b1373e in process_print_command_args /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1319 > #24 0x563f71b1391b in print_command_1 /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1332 > #25 0x563f71b147ec in print_command /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1465 > #26 0x563f706029b8 in do_simple_func /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:95 > #27 0x563f7061972a in cmd_func(cmd_list_element*, char const*, int) /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:2735 > #28 0x563f7262d0ef in execute_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/top.c:572 > #29 0x563f7100ed9c in command_handler(char const*) /home/smarchi/src/binutils-gdb/gdb/event-top.c:543 > > previously allocated by thread T0 here: > #0 0x7f5a7fce2012 in operator new(unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:95 > #1 0x563f7029a9a3 in new_momentary_breakpoint /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:8129 > #2 0x563f702212f6 in momentary_breakpoint_from_master /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:8169 > #3 0x563f70212db1 in set_longjmp_breakpoint_for_call_dummy() /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:7582 > #4 0x563f713804db in call_function_by_hand_dummy(value*, type*, gdb::array_view, void (*)(void*, int), void*) /home/smarchi/src/binutils-gdb/gdb/infcall.c:1260 > #5 0x563f7137c0e2 in call_function_by_hand(value*, type*, gdb::array_view) /home/smarchi/src/binutils-gdb/gdb/infcall.c:780 > #6 0x563f70fe5960 in evaluate_subexp_do_call(expression*, noside, value*, gdb::array_view, char const*, type*) /home/smarchi/src/binutils-gdb/gdb/eval.c:649 > #7 0x563f70fe6617 in expr::operation::evaluate_funcall(type*, expression*, noside, char const*, std::__debug::vector >, std::allocator > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:677 > #8 0x563f6fd19668 in expr::operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector >, std::allocator > > > const&) /home/smarchi/src/binutils-gdb/gdb/expression.h:136 > #9 0x563f70fe6bba in expr::var_value_operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector >, std::allocator > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:689 > #10 0x563f704b71dc in expr::funcall_operation::evaluate(type*, expression*, noside) /home/smarchi/src/binutils-gdb/gdb/expop.h:2219 > #11 0x563f70fe0f02 in expression::evaluate(type*, noside) /home/smarchi/src/binutils-gdb/gdb/eval.c:110 > #12 0x563f71b1373e in process_print_command_args /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1319 > #13 0x563f71b1391b in print_command_1 /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1332 > #14 0x563f71b147ec in print_command /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1465 > #15 0x563f706029b8 in do_simple_func /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:95 > #16 0x563f7061972a in cmd_func(cmd_list_element*, char const*, int) /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:2735 > #17 0x563f7262d0ef in execute_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/top.c:572 > #18 0x563f7100ed9c in command_handler(char const*) /home/smarchi/src/binutils-gdb/gdb/event-top.c:543 > #19 0x563f7101014b in command_line_handler(std::unique_ptr >&&) /home/smarchi/src/binutils-gdb/gdb/event-top.c:779 > #20 0x563f72777942 in tui_command_line_handler /home/smarchi/src/binutils-gdb/gdb/tui/tui-interp.c:104 > #21 0x563f7100d059 in gdb_rl_callback_handler /home/smarchi/src/binutils-gdb/gdb/event-top.c:250 > #22 0x7f5a80418246 in rl_callback_read_char (/usr/lib/libreadline.so.8+0x3b246) (BuildId: 092e91fc4361b0ef94561e3ae03a75f69398acbb) > > Change-Id: Id00c17ab677f847fbf4efdf0f4038373668d3d88 > --- > gdb/breakpoint.c | 25 ++++++++++++++++--------- > 1 file changed, 16 insertions(+), 9 deletions(-) > > diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c > index 1cc9e84c11f3..dcb00bffdbe8 100644 > --- a/gdb/breakpoint.c > +++ b/gdb/breakpoint.c > @@ -69,6 +69,7 @@ > #include "tid-parse.h" > #include "cli/cli-style.h" > #include "cli/cli-decode.h" > +#include > > /* readline include files */ > #include "readline/tilde.h" > @@ -7608,9 +7609,13 @@ set_longjmp_breakpoint_for_call_dummy (void) > void > check_longjmp_breakpoint_for_call_dummy (struct thread_info *tp) > { > - for (struct breakpoint *b : all_breakpoints_safe ()) > + /* We would need to delete breakpoints other than the current one while > + iterating, so all_breakpoints_safe is not sufficient to make that safe. > + Save all breakpoints to delete in that set and delete them at the end. */ > + std::unordered_set to_delete; Hi, For my own education: why did you choose a std::unordered_set here? I would assume that we will never find the same related breakpoint more than once. Indeed, if we did then I suspect the old code would have resulted in a double free. So why choose a set over a vector? Thanks, Andrew > + > + for (struct breakpoint *b : all_breakpoints ()) > { > - struct breakpoint *b_tmp = b->next; > if (b->type == bp_longjmp_call_dummy && b->thread == tp->global_num) > { > struct breakpoint *dummy_b = b->related_breakpoint; > @@ -7666,15 +7671,17 @@ check_longjmp_breakpoint_for_call_dummy (struct thread_info *tp) > > dummy_frame_discard (dummy_b->frame_id, tp); > > - while (b->related_breakpoint != b) > - { > - if (b_tmp == b->related_breakpoint) > - b_tmp = b->related_breakpoint->next; > - delete_breakpoint (b->related_breakpoint); > - } > - delete_breakpoint (b); > + for (breakpoint *related_breakpoint = b->related_breakpoint; > + related_breakpoint != b; > + related_breakpoint = related_breakpoint->related_breakpoint) > + to_delete.insert (b->related_breakpoint); > + > + to_delete.insert (b); > } > } > + > + for (breakpoint *b : to_delete) > + delete_breakpoint (b); > } > > void > -- > 2.40.1