c++/24367: Infinite recursion of typedef substitution
authorKeith Seitz <keiths@redhat.com>
Thu, 25 Apr 2019 20:05:51 +0000 (13:05 -0700)
committerKeith Seitz <keiths@redhat.com>
Thu, 25 Apr 2019 20:06:52 +0000 (13:06 -0700)
This bug finds another usage where we end up segfaulting while
normalizing user input.  inspect_type and replace_type recurse,
attempting to substitute the "real" symbol name for the typedef name.
However, since the both these names are the same, they keep calling
each other until the stack overflows.

A simple reproducer for it is given by

  typedef struct foo foo;
  int qux (foo *f) { return 0; }

  (gdb) b qux(foo*)
  Segmentation fault

inspect_type already contains some special handling to prevent a
similar situation from occurring with namespaces.  I wonder, however,
whether we need be so pedantic about the exact nature of the substitution.

This patch implements this rather more aggressive assumption that these
substitutions should be avoided whenever the replacement symbol's name is
exactly the same as the one we're trying to substitute.  [In the above
example, we're trying to substitute the tyepdef named "foo" with the symbol
named "foo" (a struct).]

gdb/ChangeLog:

PR c++/24367
* cp-support.c (inspect_type): Don't attempt substitutions
of symbol with the same name.

gdb/testsuite/ChangeLog:

PR c++/24367
* gdb.cp/meth-typedefs.cc (incomplete_struct)
(another_incomplete_struct, test_incomplete): New definitions.
(main): Use new definitions.
* gdb.cp/meth-typedefs.exp: Add new tests for `test_incomplete'
functions.

gdb/ChangeLog
gdb/cp-support.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.cp/meth-typedefs.cc
gdb/testsuite/gdb.cp/meth-typedefs.exp

index 17e10e869b8d542a88727e68c819eb5babb3764b..e0120e7743fa8c77cb680a3f460acc1721064df4 100644 (file)
@@ -1,3 +1,9 @@
+2019-04-25  Keith Seitz  <keiths@redhat.com>
+
+       PR c++/24367
+       * cp-support.c (inspect_type): Don't attempt substitutions
+       of symbol with the same name.
+
 2019-04-25  Tom Tromey  <tromey@adacore.com>
 
        PR gdb/24475:
index d02a01df930954fc27a2847cf99ffd99f991b6c4..4afb79a4ea9d032b23e9a49e7f5ee2bae90f10cd 100644 (file)
@@ -190,10 +190,20 @@ inspect_type (struct demangle_parse_info *info,
          /* Get the real type of the typedef.  */
          type = check_typedef (otype);
 
-         /* If the symbol is a namespace and its type name is no different
+         /* If the symbol name is the same as the original type name,
+            don't substitute.  That would cause infinite recursion in
+            symbol lookups, as the typedef symbol is often the first
+            found symbol in the symbol table.
+
+            However, this can happen in a number of situations, such as:
+
+            If the symbol is a namespace and its type name is no different
             than the name we looked up, this symbol is not a namespace
-            alias and does not need to be substituted.  */
-         if (TYPE_CODE (otype) == TYPE_CODE_NAMESPACE
+            alias and does not need to be substituted.
+
+            If the symbol is typedef and its type name is the same
+            as the symbol's name, e.g., "typedef struct foo foo;".  */
+         if (TYPE_NAME (type) != nullptr
              && strcmp (TYPE_NAME (type), name) == 0)
            return 0;
 
index c81d841e93a20b21c49231fa831f2c4ace53d3eb..9b0725a0335b046430b288d1d9f5fa4369f4a0cb 100644 (file)
@@ -1,3 +1,12 @@
+2019-04-25  Keith Seitz  <keiths@redhat.com>
+
+       PR c++/24367
+       * gdb.cp/meth-typedefs.cc (incomplete_struct)
+       (another_incomplete_struct, test_incomplete): New definitions.
+       (main): Use new definitions.
+       * gdb.cp/meth-typedefs.exp: Add new tests for `test_incomplete'
+       functions.
+
 2019-04-25  Sergio Durigan Junior  <sergiodj@redhat.com>
 
        PR corefiles/11608
index 0c4d095c7feeb382b970f8fc7091eb215604a16b..f65478e8c0f250057e83c824051ef4b390f0f5c9 100644 (file)
@@ -36,6 +36,13 @@ typedef void (*fptr2) (fptr1, my_other_type_2);
 typedef void (*fptr3) (fptr2, my_other_type);
 typedef void (*fptr4) (anon_enum a, anon_struct const& b, anon_union const*** c);
 
+// For c++/24367 testing
+typedef struct incomplete_struct incomplete_struct;
+typedef struct _incomplete_struct another_incomplete_struct;
+int test_incomplete (incomplete_struct *p) { return 0; } // test_incomplete(incomplete_struct*)
+int test_incomplete (another_incomplete_struct *p) { return 1; } // test_incomplete(another_incomplete_struct*)
+int test_incomplete (int *p) { return -1; } // test_incomplete(int*)
+
 namespace A
 {
   class foo
@@ -147,5 +154,11 @@ main (void)
 
   fptr4 f4;
 
+  // Tests for c++/24367
+  int *i = nullptr;
+  incomplete_struct *is = nullptr;
+  another_incomplete_struct *ais = nullptr;
+  int result = (test_incomplete (i) + test_incomplete (is)
+               + test_incomplete (ais));
   return 0;
 }
index b9c383bb2502218026e6c88a7c46bf7bee5d39dc..76a8fc9780826e1b23ff0aca9ca271671761db64 100644 (file)
@@ -137,6 +137,11 @@ foreach t $typedefs(_BAR_) {
     add methods "test" "$t&" {_BAR_&}
 }
 
+# Tests for c++/24367
+foreach t {int incomplete_struct another_incomplete_struct} {
+    add methods "test_incomplete" "${t}*" [string_to_regexp "${t}*"]
+}
+
 gdb_test_no_output "set listsize 1" ""
 
 # Finally, for each method in the list METHODS, check whether