Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH v3 0/2] [gdb/exp] Fix ignoring of incorrect namespace prefix
@ 2026-04-10 12:11 Tom de Vries
  2026-04-10 12:11 ` [PATCH v3 1/2] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports Tom de Vries
  2026-04-10 12:11 ` [PATCH v3 2/2] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
  0 siblings, 2 replies; 6+ messages in thread
From: Tom de Vries @ 2026-04-10 12:11 UTC (permalink / raw)
  To: gdb-patches

Hafiz Abid Qadeer reported a problem with namespace handling using a Fortran
program [1].  I wrote an equivalent program in C++, and reproduced the
reported problem with both.  While investigating the problem, I ran into
another problem, for which I filed PR34051.

This series contains two patches.

The first patch refactors a complex assignment in
cp_lookup_symbol_via_imports.

The second patch fixes PR34051, in that same assignment.

Tested on aarch64-linux.

A v1 was submitted here [2].

New in v2 [3]:
- updated type of directive_match to bool

New in v3:
- fixed top-level "return -1" in test-case
- fixed typo in test-case

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34051

[1] https://sourceware.org/bugzilla/show_bug.cgi?id=34034
[2] v1 https://sourceware.org/pipermail/gdb-patches/2026-April/226370.html
[3] v2 https://sourceware.org/pipermail/gdb-patches/2026-April/226375.html

Tom de Vries (2):
  [gdb] Break up complex assignment in cp_lookup_symbol_via_imports
  [gdb/exp] Fix ignoring of incorrect namespace prefix

 gdb/cp-namespace.c                 | 28 ++++++++---
 gdb/testsuite/gdb.cp/nsusing-2.cc  | 39 ++++++++++++++++
 gdb/testsuite/gdb.cp/nsusing-2.exp | 75 ++++++++++++++++++++++++++++++
 3 files changed, 135 insertions(+), 7 deletions(-)
 create mode 100644 gdb/testsuite/gdb.cp/nsusing-2.cc
 create mode 100644 gdb/testsuite/gdb.cp/nsusing-2.exp


base-commit: 65e4798d49afe18c20acd5f5830e706b175ba844
-- 
2.51.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v3 1/2] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports
  2026-04-10 12:11 [PATCH v3 0/2] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
@ 2026-04-10 12:11 ` Tom de Vries
  2026-04-14 17:49   ` Tom Tromey
  2026-04-10 12:11 ` [PATCH v3 2/2] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
  1 sibling, 1 reply; 6+ messages in thread
From: Tom de Vries @ 2026-04-10 12:11 UTC (permalink / raw)
  To: gdb-patches

In cp_lookup_symbol_via_imports, we have a complex assignment:
...
      directive_match = (search_parents
                        ? (startswith (scope, current->import_dest)
                           && (len == 0
                               || scope[len] == ':'
                               || scope[len] == '\0'))
                        : streq (scope, current->import_dest));
...

Writing it like this makes it:
- harder to comment on parts of the expression, and also
- harder to understand and modify it.

Also, len == 0 makes the startswith redundant, so that part of the expression
can be hoisted.  Doing so makes it clear that scope is not compared against in
all cases.

Fix this by breaking this up into three separate assignments:
...
      if (search_parents)
        {
          if (len == 0)
            directive_match = 1;
          else
            directive_match = (startswith (scope, current->import_dest)
                               && (scope[len] == ':'
                                   || scope[len] == '\0'));
        }
      else
        directive_match = streq (scope, current->import_dest);
...
---
 gdb/cp-namespace.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index c8cd5c245aa..f8b71be3ff1 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -394,7 +394,6 @@ cp_lookup_symbol_via_imports (const char *scope,
 {
   struct block_symbol sym = {};
   int len;
-  int directive_match;
 
   /* All the symbols we found will be kept in this relational map between
      the mangled name and the block_symbol found.  We do this so that GDB
@@ -425,13 +424,21 @@ cp_lookup_symbol_via_imports (const char *scope,
 	 do not use this directive.  */
       if (!current->valid_line (boundary_sal.line))
 	continue;
+
       len = strlen (current->import_dest);
-      directive_match = (search_parents
-			 ? (startswith (scope, current->import_dest)
-			    && (len == 0
-				|| scope[len] == ':'
-				|| scope[len] == '\0'))
-			 : streq (scope, current->import_dest));
+
+      bool directive_match;
+      if (search_parents)
+	{
+	  if (len == 0)
+	    directive_match = 1;
+	  else
+	    directive_match = (startswith (scope, current->import_dest)
+			       && (scope[len] == ':'
+				   || scope[len] == '\0'));
+	}
+      else
+	directive_match = streq (scope, current->import_dest);
 
       /* If the import destination is the current scope or one of its
 	 ancestors then it is applicable.  */
-- 
2.51.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v3 2/2] [gdb/exp] Fix ignoring of incorrect namespace prefix
  2026-04-10 12:11 [PATCH v3 0/2] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
  2026-04-10 12:11 ` [PATCH v3 1/2] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports Tom de Vries
@ 2026-04-10 12:11 ` Tom de Vries
  2026-04-14 18:26   ` Tom Tromey
  1 sibling, 1 reply; 6+ messages in thread
From: Tom de Vries @ 2026-04-10 12:11 UTC (permalink / raw)
  To: gdb-patches

Consider test.c, compiled to a.out using "g++ -g test.c":
...
     1  namespace mod_a { int xxx = 10; }
     2  namespace mod_b { using namespace mod_a;
     3                    int yyy = 20; }
     4  int main (void) {
     5    using namespace mod_b;
     6    void (xxx + yyy);
     7    return 0;
     8  }
...

When trying to print the value of non-existent variable mod_a::yyy, we get:
...
$ gdb -q -batch a.out -ex start -ex "print mod_a::yyy"
  ...
Temporary breakpoint 1, main () at test.c:7
7         return 0;
$1 = 20
...

The problem is in cp_lookup_symbol_via_imports, where we decide that the
"using namespace mod_b" from main is applicable in scope mod_a.

Fix this by being more strict in the calculation of directive_match:
...
          if (len == 0)
-           directive_match = 1;
+           {
+             const char *current_scope = (block->function () != nullptr
+                                          ? block->scope ()
+                                          : nullptr /* Don't know.  */);
+             directive_match = (current_scope != nullptr
+                                ? streq (scope, current_scope)
+                                : 1 /* Assume there's a match.  */);
+           }
...

As is clear from the code, in case we don't know the current scope, we assume
there's a match.  This may be harmless, or this may describe a cornercase we
haven't run into yet.  If so, it's a pre-existing issue.

The new test-case contains regression tests for:
- PR34051, and
- PR34034 for which it contains a kfail.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34051
---
 gdb/cp-namespace.c                 |  9 +++-
 gdb/testsuite/gdb.cp/nsusing-2.cc  | 39 ++++++++++++++++
 gdb/testsuite/gdb.cp/nsusing-2.exp | 75 ++++++++++++++++++++++++++++++
 3 files changed, 122 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.cp/nsusing-2.cc
 create mode 100644 gdb/testsuite/gdb.cp/nsusing-2.exp

diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c
index f8b71be3ff1..45cde597674 100644
--- a/gdb/cp-namespace.c
+++ b/gdb/cp-namespace.c
@@ -431,7 +431,14 @@ cp_lookup_symbol_via_imports (const char *scope,
       if (search_parents)
 	{
 	  if (len == 0)
-	    directive_match = 1;
+	    {
+	      const char *current_scope = (block->function () != nullptr
+					   ? block->scope ()
+					   : nullptr /* Don't know.  */);
+	      directive_match = (current_scope != nullptr
+				 ? streq (scope, current_scope)
+				 : 1 /* Assume there's a match.  */);
+	    }
 	  else
 	    directive_match = (startswith (scope, current->import_dest)
 			       && (scope[len] == ':'
diff --git a/gdb/testsuite/gdb.cp/nsusing-2.cc b/gdb/testsuite/gdb.cp/nsusing-2.cc
new file mode 100644
index 00000000000..72f98add1b9
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/nsusing-2.cc
@@ -0,0 +1,39 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2026 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* C++ variant of the Fortran example from PR34034.  */
+
+namespace mod_a {
+  int xxx = 10;
+}
+
+namespace mod_b {
+  using namespace mod_a;
+  int yyy = 20;
+}
+
+static void foo () {}
+
+int
+main (void)
+{
+  foo ();	/* main-entry.  */
+  using namespace mod_b;
+  (void)xxx;
+  (void)yyy;
+  return 0;	/* main-return.  */
+}
diff --git a/gdb/testsuite/gdb.cp/nsusing-2.exp b/gdb/testsuite/gdb.cp/nsusing-2.exp
new file mode 100644
index 00000000000..647a8600955
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/nsusing-2.exp
@@ -0,0 +1,75 @@
+# Copyright 2026 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test recursive "using namespace".  Regression test for PR34034 and PR34051.
+
+standard_testfile .cc
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile \
+	 {debug c++}]} {
+    return
+}
+
+with_test_prefix pre-main {
+    gdb_test "print mod_a::xxx" " = 10"
+    gdb_test "print mod_b::yyy" " = 20"
+
+    # Namespace mod_b is using namespace mod_a, so mod_a::xxx is available as
+    # mod_b::xxx.  This is not available here though, but later, at
+    # start-of-main.  I wonder if this should also be available here.
+    gdb_test "print mod_b::xxx" \
+	[string_to_regexp {No symbol "xxx" in namespace "mod_b".}]
+}
+
+set line_main_entry [gdb_get_line_number main-entry]
+if {![runto $srcfile:$line_main_entry]} {
+    return
+}
+
+# Start of main.  Function main is not yet using namespace mod_b.
+with_test_prefix start-of-main {
+    # Namespace mod_b is using namespace mod_a, so mod_a::xxx is available as
+    # mod_b::xxx.  See also the note at the identical command in pre-main.
+    gdb_test "print mod_b::xxx" " = 10"
+
+    # Same command as in end-of-main, but not a regression test for PR34034.
+    gdb_test "print xxx" \
+	[string_to_regexp {No symbol "xxx" in current context.}]
+
+    # Same test as in end-of-main, but not a regression test for PR34051.
+    gdb_test "print mod_a::yyy" \
+	[string_to_regexp {No symbol "yyy" in namespace "mod_a".}]
+}
+
+set line_main_return [gdb_get_line_number "main-return"]
+gdb_test "next" \
+    [subst_vars {$line_main_return\t[^\r\n]+}]
+
+# End of main.  Function main is using namespace mod_b.
+with_test_prefix end-of-main {
+    # Function main is using namespace mod_b, so mod_b::yyy is available as
+    # yyy.
+    gdb_test "print yyy" " = 20"
+
+    # Function main is using namespace mod_b, and namespace mod_b is using
+    # namespace mod_a, so mod_a::xxx is available as xxx.  Regression test for
+    # PR34034.
+    setup_kfail exp/34034 *-*-*
+    gdb_test "print xxx" " = 10"
+
+    # This used to print " $<n> = 20".  Regression test for PR34051.
+    gdb_test "print mod_a::yyy" \
+	[string_to_regexp {No symbol "yyy" in namespace "mod_a".}]
+}
-- 
2.51.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 1/2] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports
  2026-04-10 12:11 ` [PATCH v3 1/2] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports Tom de Vries
@ 2026-04-14 17:49   ` Tom Tromey
  0 siblings, 0 replies; 6+ messages in thread
From: Tom Tromey @ 2026-04-14 17:49 UTC (permalink / raw)
  To: Tom de Vries; +Cc: gdb-patches

>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:

Tom> +	  if (len == 0)
Tom> +	    directive_match = 1;

Should be "= true".
Ok with this tweak.
Approved-By: Tom Tromey <tom@tromey.com>

Tom

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 2/2] [gdb/exp] Fix ignoring of incorrect namespace prefix
  2026-04-10 12:11 ` [PATCH v3 2/2] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
@ 2026-04-14 18:26   ` Tom Tromey
  2026-04-15 10:12     ` Tom de Vries
  0 siblings, 1 reply; 6+ messages in thread
From: Tom Tromey @ 2026-04-14 18:26 UTC (permalink / raw)
  To: Tom de Vries; +Cc: gdb-patches

>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:

Tom> @@ -431,7 +431,14 @@ cp_lookup_symbol_via_imports (const char *scope,

I find this function and related functions pretty hard to follow, so I'm
not really sure about the bug or the patch, but:

Tom> +	      const char *current_scope = (block->function () != nullptr
Tom> +					   ? block->scope ()
Tom> +					   : nullptr /* Don't know.  */);

... this line struck me as a bit weird, in that block->function() isn't
set for all blocks inside a function, so this would mean that stepping
into some nested block would seem to reproduce the bug again.

Tom

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 2/2] [gdb/exp] Fix ignoring of incorrect namespace prefix
  2026-04-14 18:26   ` Tom Tromey
@ 2026-04-15 10:12     ` Tom de Vries
  0 siblings, 0 replies; 6+ messages in thread
From: Tom de Vries @ 2026-04-15 10:12 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 4/14/26 8:26 PM, Tom Tromey wrote:
>>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:
> 
> Tom> @@ -431,7 +431,14 @@ cp_lookup_symbol_via_imports (const char *scope,
> 
> I find this function and related functions pretty hard to follow, so I'm
> not really sure about the bug or the patch, but:
> 
> Tom> +	      const char *current_scope = (block->function () != nullptr
> Tom> +					   ? block->scope ()
> Tom> +					   : nullptr /* Don't know.  */);
> 
> ... this line struck me as a bit weird, in that block->function() isn't
> set for all blocks inside a function, so this would mean that stepping
> into some nested block would seem to reproduce the bug again.

Hi Tom,

thanks for the review.

I've extended the test-case with the nested block scenario you describe, 
and indeed the bug reproduced again.  I've fixed that by checking for 
"block->function_block () != nullptr" instead.

V4 submitted here ( 
https://sourceware.org/pipermail/gdb-patches/2026-April/226488.html ).

Thanks,
- Tom


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-04-15 10:12 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-04-10 12:11 [PATCH v3 0/2] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
2026-04-10 12:11 ` [PATCH v3 1/2] [gdb] Break up complex assignment in cp_lookup_symbol_via_imports Tom de Vries
2026-04-14 17:49   ` Tom Tromey
2026-04-10 12:11 ` [PATCH v3 2/2] [gdb/exp] Fix ignoring of incorrect namespace prefix Tom de Vries
2026-04-14 18:26   ` Tom Tromey
2026-04-15 10:12     ` Tom de Vries

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox