From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id +se8COMy4mohsj4AWB0awg (envelope-from ) for ; Wed, 28 Oct 2026 13:37:39 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=d6aipcZy; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 0D312378002; Wed, 28 Oct 2026 13:37:39 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-6.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,WEIRD_PORT autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 93B0B1E007 for ; Wed, 28 Oct 2026 13:37:37 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CD7334BA23CC for ; Wed, 28 Oct 2026 17:37:35 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CD7334BA23CC Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=d6aipcZy Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 299114BA2E1D for ; Wed, 28 Oct 2026 17:37:06 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 299114BA2E1D Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 299114BA2E1D Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1793209026; cv=none; b=KvmOh2SFbEe0NLog9H26E1J7obulwTknoA2ENC64/Gw9ISKiGHLQmELNLITAKWH+gXASvLQcJKzd3XjhTa/tUNQNnEiDRRihqCjauox+/RkVM6TAqe7/Wrd8ZfMtmTkAg5IwPVkOGYiWAXD+RX/ByQ0K3HTMGWO9vfbbeuHJyXc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1793209026; c=relaxed/simple; bh=kERf37GFCCO0wxp/EbrsKDFs98BKGmID0dfTj/UYnz4=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=fV9YN8ETPFwhtcNB3r6Zl928Kv9xJgQZS1gDWNXtSb8DnWd0a6+Irf6wvZhAEbPn2Fz1yEKuEToPMGsTYt/sLyyEgpe+RDYAHqN2kjV8Ta80jh3FkPyPGmHAkvoiiHjs5Xdqcbh0jvknXyx/RamENgryo56lo5/3/HABhTz3/wE= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=d6aipcZy DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 299114BA2E1D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1793209025; 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=gysmyYOQhJ9pHKg61aAicQhy6bejDtpt+lvHV+K0ef0=; b=d6aipcZyynUtD9mlJE4d+f0t0TADXfq4ENUbURI/jPezBfBwbI3Vu0QcNnRupTVJBzS/tf Uk6VpcGaoESMuGwit6gqEMAHNRdL1CI/bpzDLQgdAU2YWZrOlc7i4XaOi6kD7Od7Ehyi++ 3SlU87asCm+o1K3NLP7UtdjBOzRc5Rw= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-412-LR6MQzKONBycsM0m4xD_HQ-1; Wed, 28 Oct 2026 13:37:04 -0400 X-MC-Unique: LR6MQzKONBycsM0m4xD_HQ-1 X-Mimecast-MFC-AGG-ID: LR6MQzKONBycsM0m4xD_HQ_1793209023 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-4a2001e85c8so9204935e9.1 for ; Wed, 28 Oct 2026 10:37:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793209023; x=1793813823; h=content-type:mime-version:message-id:date:references:in-reply-to :subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject :date:message-id:reply-to:content-type; bh=gysmyYOQhJ9pHKg61aAicQhy6bejDtpt+lvHV+K0ef0=; b=jNsKdx2A1bF2KSqL0CnsTSKJIeUDSWAvCG+Jy4GRQyueeWpM3YZifGqiOJgd0rmSQz VUati9A5YKOXFtssc0Suolrf2VmwoxrJSDwJPFrABGpxkUu0YYSGDWArKqMvXnTnrrPc zLqiO0VsnWr+Rg6TbzqnDicn5EuE671VJyHcu8cfZJheZYLJ8tN4sAHvCY2XCN5Twsjb XNzA5g0Nc621HFnXQUlq1wwcrafHnt/OodyH13qPJpTUTEBqsYM7VfyXXX5hBSTt1HJJ C5jE3gtdJW1xTwsTt7R2GLHHMmdBbl0cJgjLA+6u6Ot7Jr1tbbGK0XUN9BMWgYzsoqYR UAkQ== X-Forwarded-Encrypted: i=1; AKwUvBxHl9o1g5uGboT1k7MxZ42IOq/+Jk0fOXhlhTKLFo/cwiJZi1z+M1pdUVgrN2IPsb7h25dy81cvevd3tQ==@sourceware.org X-Gm-Message-State: AFq9FYIHp33Yc80HxRNmkfLoWzoTcqxotDiqMu238Aw8Oy1dyHCf2DYi Pka4NIEBtGayfoQ+XICxfHPxGLyq3CInGZTEEncLO/w2CdQ6qvvqFNzN49lELTKB63mbl75k4iu OwgF+ilKM0z0DFCT+KPHxTLTRLSrnCTZjwUcnMpbE2avLVvu22JTGw+IIu8REvHteSypSifw= X-Gm-Gg: AYBFou12xyI4Qi9HPGh/O4QWKCxF3gYhII/ywsC9rBHj5W1Fvu+COkJ9E2dhDB6DrIC T8rCErAUXOcdP9ASzdSAiOm2yaRAXdcYbm7RWUfjenAPLwl7u6JfYE4Sd6ng2L5yiDxEyPK9cnb UCJrTOLEI2wHVC3dR3RmRQ+sDszI1EY3XW++yWUc/NBCTpLie0F1aip5zTzIty161MLNta6mPlE Fr+rUc0rJIQcYGT3+gKC7vB07dAWMYc1LjPotoRRXb27tK2SKHsCG584IgjRhdN3oAoOMZ86wNk qQZAU4KqbcrZwO1ILcPV/Ly8iMMjRJQbUwo1T9AhNmMQZ1TBG2vnFHG9GovzCUodGUdmaLjbYf0 HSlVugieuhAwaoxiTQybYaek2/j+gaXPo4JK4SzsZhdfVIt8= X-Received: by 2002:a05:600c:8b28:b0:4a5:75d2:c104 with SMTP id 5b1f17b1804b1-4a96720304cmr69831745e9.22.1793209022764; Wed, 28 Oct 2026 10:37:02 -0700 (PDT) X-Received: by 2002:a05:600c:8b28:b0:4a5:75d2:c104 with SMTP id 5b1f17b1804b1-4a96720304cmr69830925e9.22.1793209022176; Wed, 28 Oct 2026 10:37:02 -0700 (PDT) Received: from localhost ([2a00:23c6:e11d:fb01:6748:4fce:3e30:6e23]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-48e3ecdf9bdsm28398224f8f.55.2026.10.28.10.37.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Oct 2026 10:37:01 -0700 (PDT) From: Andrew Burgess To: Simon Marchi , gdb-patches@sourceware.org Cc: Simon Marchi Subject: Re: [PATCH 2/2] gdb/macrotab: catch exception and rethrow around splay_tree_foreach In-Reply-To: <20261026144606.1941722-2-simon.marchi@efficios.com> References: <20261026144606.1941722-1-simon.marchi@efficios.com> <20261026144606.1941722-2-simon.marchi@efficios.com> Date: Wed, 28 Oct 2026 17:37:00 +0000 Message-ID: <87mrrx7mmb.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Q8cfaGe8_OxAsrXLAZ9taftrPomHeB6yzbyu6qt471U_1793209023 X-Mimecast-Originator: redhat.com Content-Type: text/plain X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Simon Marchi writes: > From: Simon Marchi > > Bug 34876 talks about a crash that happens with "-O3 -flto", when > completing and reaching the maximum number of completions. > > It can be reproduced by building GDB in this configuration: > > $ ./configure CFLAGS="-march=x86-64-v3 -flto -O3" CXXFLAGS="-march=x86-64-v3 -flto -O3" --disable-nls > > Then, using a dummy C program compiled with "gcc -g3", this crashes GDB: > > $ ./gdb -q -nx --data-directory data-directory ./a.out -ex list -ex "complete macro expand " > > The crash manifests as an invalid free, reported by glibc: > > free(): invalid pointer > > It is reported here: > > #0 0x00007ffff6a9a11c in ?? () from /usr/lib/libc.so.6 > #1 0x00007ffff6a3e5d0 in raise () from /usr/lib/libc.so.6 > #2 0x00007ffff6a25685 in abort () from /usr/lib/libc.so.6 > #3 0x00007ffff6a26704 in ?? () from /usr/lib/libc.so.6 > #4 0x00007ffff6aa47ec in ?? () from /usr/lib/libc.so.6 > #5 0x00007ffff6aa4804 in ?? () from /usr/lib/libc.so.6 > #6 0x00005555556e07ac in operator delete (p=) at /home/simark/src/binutils-gdb/gdbsupport/new-op.cc:108 > #7 operator delete (p=) at /home/simark/src/binutils-gdb/gdbsupport/new-op.cc:114 > #8 operator delete (p=) at /home/simark/src/binutils-gdb/gdbsupport/new-op.cc:120 > #9 std::__new_allocator::deallocate (this=0x555555caa4f8 , __p=, __n=) at /usr/include/c++/16/bits/new_allocator.h:183 > #10 std::allocator::deallocate (this=0x555555caa4f8 , __p=, __n=) at /usr/include/c++/16/bits/allocator.h:218 > #11 std::allocator_traits >::deallocate (__a=..., __p=, __n=) at /usr/include/c++/16/bits/alloc_traits.h:689 > #12 std::__cxx11::basic_string, std::allocator >::_M_destroy (this=0x555555caa4f8 , __size=) at /usr/include/c++/16/bits/basic_string.h:304 > #13 std::__cxx11::basic_string, std::allocator >::_M_dispose (this=0x555555caa4f8 ) at /usr/include/c++/16/bits/basic_string.h:298 > #14 std::__cxx11::basic_string, std::allocator >::~basic_string (this=0x555555caa4f8 , this=) at /usr/include/c++/16/bits/basic_string.h:920 > #15 demangle_for_lookup_info::~demangle_for_lookup_info (this=0x555555caa4f8 , this=) at /home/simark/src/binutils-gdb/gdb/symtab.h:183 > #16 std::_Optional_payload_base::_M_destroy (this=0x555555caa4f8 ) at /usr/include/c++/16/optional:325 > #17 std::_Optional_payload_base::_M_reset (this=0x555555caa4f8 ) at /usr/include/c++/16/optional:361 > #18 std::_Optional_payload::~_Optional_payload (this=0x555555caa4f8 , this=) at /usr/include/c++/16/optional:484 > #19 std::_Optional_base::~_Optional_base (this=0x555555caa4f8 , this=) at /usr/include/c++/16/optional:508 > #20 std::optional::~optional (this=0x555555caa4f8 , this=) at /usr/include/c++/16/optional:812 > #21 lookup_name_info::~lookup_name_info (this=0x555555caa440 ::bind(default_collect_symbol_completion_matches_break_on(completion_tracker&, complete_symbol_mode, symbol_name_match_type, char const*, char const*, char const*, type_code)::{lambda(char const*, macro_definition const*, macro_source_file*, int)#1}&)::{lambda(gdb::fv_detail::erased_callable, char const*, macro_definition const*, macro_source_file*, int)#1}::_FUN(gdb::fv_detail::erased_callable, char const*, macro_definition const*, macro_source_file*, int)>, this=) at /home/simark/src/binutils-gdb/gdb/symtab.h:210 > #22 0x000055555569ca89 in default_collect_symbol_completion_matches_break_on (tracker=..., mode=, name_match_type=, text=, word=, break_on=, code=) at /home/simark/src/binutils-gdb/gdb/symtab.c:6111 > #23 0x0000555555826c22 in language_defn::collect_symbol_completion_matches (this=, tracker=..., mode=, name_match_type=, text=, word=, code=, this=, tracker=..., mode=, name_match_type=, text=, word=, code=) at /home/simark/src/binutils-gdb/gdb/language.h:477 > #24 collect_symbol_completion_matches (tracker=..., mode=complete_symbol_mode::EXPRESSION, name_match_type=symbol_name_match_type::EXPRESSION, text=, word=) at /home/simark/src/binutils-gdb/gdb/symtab.c:6122 > #25 symbol_completer (ignore=, tracker=..., text=, word=) at /home/simark/src/binutils-gdb/gdb/completer.c:1533 > #26 0x000055555583ef85 in complete_line_internal_normal_command (command=0x7fffffffd880 "macro expand ", tracker=..., word=0x7fffffffd88d "", cmd_args=, reason=handle_completions, c=0x5555563b02c0) at /home/simark/src/binutils-gdb/gdb/completer.c:1620 > #27 complete_line_internal_1 (tracker=..., text=text@entry=0x7fffffffe7e2 "", line_buffer=line_buffer@entry=0x7fffffffe7d5 "macro expand ", point=, reason=reason@entry=handle_completions) at /home/simark/src/binutils-gdb/gdb/completer.c:1843 > #28 0x000055555583fe81 in complete_line_internal (tracker=..., text=0x7fffffffe7e2 "", line_buffer=, point=, reason=handle_completions) at /home/simark/src/binutils-gdb/gdb/completer.c:1862 > #29 complete_line (tracker=..., text=0x7fffffffe7e2 "", line_buffer=, point=) at /home/simark/src/binutils-gdb/gdb/completer.c:2157 > #30 complete_line (tracker=..., text=0x7fffffffe7e2 "", line_buffer=, point=) at /home/simark/src/binutils-gdb/gdb/completer.c:2152 > #31 complete(char const*, char const**, int*) [clone .constprop.0] (line=0x7fffffffe7d5 "macro expand ", word=0x7fffffffdb88, quote_char=) at /home/simark/src/binutils-gdb/gdb/completer.c:2126 > #32 0x00005555557e16db in complete_command (arg=0x7fffffffe7d5 "macro expand ", from_tty=) at /home/simark/src/binutils-gdb/gdb/cli/cli-cmds.c:425 > > I asked Claude to find the root cause, and it came up with the following > explanation: > > 1. With -batch, or after 200 matches interactively, > completion_tracker::add_completion throws > MAX_COMPLETIONS_REACHED_ERROR. > > 2. That throw happens inside the add_macro_name callback, which is called > from libiberty's splay_tree_foreach (C code) via > foreach_macro_in_scope in gdb/macrotab.c. > > 3. libiberty is compiled as C without -fexceptions, so GCC treats > splay_tree_foreach as nothrow. With LTO, GCC can see that across > translation units, so it decides macro_for_each_in_scope can't throw > either. It then compiles the call at symtab.c:6052 as non-throwing. > > 4. At runtime the exception still unwinds, because x86-64 has CFI > everywhere. But it lands in a landing pad that doesn't belong to that > call site. That pad runs ~lookup_name_info() with this = %rbx. At the > throwing call, %rbx actually holds the function_view invoker address > (0x555555b32780, a code address), so it destroys garbage and hands a > bogus pointer to free(). > > I can't tell for sure that it's correct, but it sounds very plausible to > me (the address 0x555555b32780 is from another run on another computer, not > related to the backtrace above). > > On x86-64, the psABI mandates that all programs and libraries have an async > unwind table (.eh_frame), so the exception is able to go through the C > frames unnoticed most of the time. But on ARM, for example, programs don't > have unwind tables by default. I was able to reproduce the bug on my old > Raspberry Pi running an outdated Debian: > > (gdb) show version > GNU gdb (Raspbian 10.1-1.7) 10.1.90.20210103-git > ... > (gdb) list > 1 int main() > 2 { > 3 } > (gdb) complete macro expand > terminate called after throwing an instance of 'gdb_exception_error' > Aborted > > There, the exception causes std::terminate to be called as soon as it > reaches the libiberty C frame. > > This patch updates the two callbacks passed to splay_tree_foreach in > this file (foreach_macro and foreach_macro_in_scope) to catch any > exception that would escape, stash it in macro_for_each_data::exception, > and return 1 to stop the splay tree iteration. The caller of > splay_tree_foreach then rethrows the exception if there is one. > > Since I'm re-indenting the code anyway, I took the opportunity to > modernize it a bit. > > Improve gdb.base/macscp.exp to kind of cover this. The test won't catch > the bug on a regular x86-64 build, but it would in an LTO build like in > the bug report, or on ARM without unwind tables. It would also catch it > if we just added "noexcept" to the callbacks. > > There is another latent instance of this bug in addrmap.c, where we call > splay_tree_foreach and the callback can throw. And probably more when > using other APIs. As future work, I propose that we go over all the > callbacks that we pass to a C API to mark them "noexcept", so that these > cases of exceptions crossing C frames consistently crash GDB on any > configuration. And fix them if necessary to catch and rethrow > exceptions like done in this patch. > > Change-Id: Ie7c4515a4dee1c93b04271f1d5057be23c96c039 > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34876 > --- > gdb/macrotab.c | 73 ++++++++++++++++++++----------- > gdb/testsuite/gdb.base/macscp.exp | 27 ++++++++++++ > 2 files changed, 75 insertions(+), 25 deletions(-) > > diff --git a/gdb/macrotab.c b/gdb/macrotab.c > index 078eb5cb5aa7..a9b678b32e70 100644 > --- a/gdb/macrotab.c > +++ b/gdb/macrotab.c > @@ -945,22 +945,31 @@ struct macro_for_each_data > gdb::function_view fn; > struct macro_source_file *file; > int line; > + std::exception_ptr exception; > }; > > /* Helper function for macro_for_each. */ > static int > -foreach_macro (splay_tree_node node, void *arg) > +foreach_macro (splay_tree_node node, void *arg) noexcept > { > - struct macro_for_each_data *datum = (struct macro_for_each_data *) arg; > - struct macro_key *key = (struct macro_key *) node->key; > - struct macro_definition *def; > + auto datum = static_cast (arg); > > - std::string key_fullname = macro_source_fullname (key->start_file); > - def = fixup_definition (key_fullname.c_str (), key->start_line, > - (struct macro_definition *) node->value); > + try > + { > + auto key = reinterpret_cast (node->key); > + auto value = reinterpret_cast (node->value); > + std::string key_fullname = macro_source_fullname (key->start_file); > + macro_definition *def = fixup_definition (key_fullname.c_str (), > + key->start_line, value); > > - datum->fn (key->name, def, key->start_file, key->start_line); > - return 0; > + datum->fn (key->name, def, key->start_file, key->start_line); > + return 0; > + } > + catch (...) > + { > + datum->exception = std::current_exception (); > + return 1; > + } > } > > /* Call FN for every macro in TABLE. */ > @@ -974,28 +983,39 @@ macro_for_each (struct macro_table *table, > datum.file = NULL; Given you are modernising the code anyway, maybe NULL -> nullptr here? But otherwise, this looks great. The approach and implementation make sense to me. Thanks for fixing this. Approved-By: Andrew Burgess Thanks, Andrew > datum.line = 0; > splay_tree_foreach (table->definitions, foreach_macro, &datum); > + > + if (datum.exception != nullptr) > + std::rethrow_exception (datum.exception); > } > > static int > -foreach_macro_in_scope (splay_tree_node node, void *info) > +foreach_macro_in_scope (splay_tree_node node, void *info) noexcept > { > - struct macro_for_each_data *datum = (struct macro_for_each_data *) info; > - struct macro_key *key = (struct macro_key *) node->key; > - struct macro_definition *def; > + auto datum = static_cast (info); > > - std::string datum_fullname = macro_source_fullname (datum->file); > - def = fixup_definition (datum_fullname.c_str (), datum->line, > - (struct macro_definition *) node->value); > + try > + { > + auto key = reinterpret_cast (node->key); > + auto value = reinterpret_cast (node->value); > + std::string datum_fullname = macro_source_fullname (datum->file); > + macro_definition *def = fixup_definition (datum_fullname.c_str (), > + datum->line, value); > > - /* See if this macro is defined before the passed-in line, and > - extends past that line. */ > - if (compare_locations (key->start_file, key->start_line, > - datum->file, datum->line) < 0 > - && (!key->end_file > - || compare_locations (key->end_file, key->end_line, > - datum->file, datum->line) >= 0)) > - datum->fn (key->name, def, key->start_file, key->start_line); > - return 0; > + /* See if this macro is defined before the passed-in line, and > + extends past that line. */ > + if (compare_locations (key->start_file, key->start_line, > + datum->file, datum->line) < 0 > + && (key->end_file == nullptr > + || compare_locations (key->end_file, key->end_line, > + datum->file, datum->line) >= 0)) > + datum->fn (key->name, def, key->start_file, key->start_line); > + return 0; > + } > + catch (...) > + { > + datum->exception = std::current_exception (); > + return 1; > + } > } > > /* Call FN for every macro is visible in SCOPE. */ > @@ -1010,6 +1030,9 @@ macro_for_each_in_scope (struct macro_source_file *file, int line, > datum.line = line; > splay_tree_foreach (file->table->definitions, > foreach_macro_in_scope, &datum); > + > + if (datum.exception != nullptr) > + std::rethrow_exception (datum.exception); > } > > > diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp > index e40bfb633378..e0bcddb9312b 100644 > --- a/gdb/testsuite/gdb.base/macscp.exp > +++ b/gdb/testsuite/gdb.base/macscp.exp > @@ -14,6 +14,7 @@ > # You should have received a copy of the GNU General Public License > # along with this program. If not, see . > > +load_lib completion-support.exp > > standard_testfile macscp1.c > set objfile [standard_output_file ${testfile}.o] > @@ -750,3 +751,29 @@ gdb_test "macro expand siginfo.si_addr" \ > gdb_test "print __FILE__" " = \".*macscp1.c\"" > gdb_test "print __LINE__" \ > " = [gdb_get_line_number {stopping point for line test}]" > + > +# Regression test for bug 34876. > + > +with_test_prefix "max-completions reached" { > + with_set max-completions 2 { > + # Macros from the program, visited by foreach_macro_in_scope. All > + # the BEFORE_ macros are in scope at this point. The macros > + # are visited in alphabetical order. > + test_gdb_complete_multiple "macro expand " "BEFORE_" "MACSCP1_" { > + "BEFORE_MACSCP1_1" > + "BEFORE_MACSCP1_2" > + } "" "" true "program macros" > + > + # User-defined macros, visited by foreach_macro. > + gdb_test_no_output "macro define USER_MACRO_A 1" > + gdb_test_no_output "macro define USER_MACRO_B 2" > + gdb_test_no_output "macro define USER_MACRO_C 3" > + test_gdb_complete_multiple "macro expand " "USER_MACRO_" "" { > + "USER_MACRO_A" > + "USER_MACRO_B" > + } "" "" true "user macros" > + gdb_test_no_output "macro undef USER_MACRO_A" > + gdb_test_no_output "macro undef USER_MACRO_B" > + gdb_test_no_output "macro undef USER_MACRO_C" > + } > +} > -- > 2.56.0