[4,PR,gdb/16959] gdb hangs in infinite recursion

Message ID 1522101276-114428-1-git-send-email-weimin.pan@oracle.com
State Superseded
Headers show
Series
  • [4,PR,gdb/16959] gdb hangs in infinite recursion
Related show

Commit Message

Weimin Pan March 26, 2018, 9:54 p.m.
The original problem was fixed (see related PR 22242). But using a typedef
as the declared type for a static member variable, as commented in this PR,
is still causing gdb to get into infinite loop when printing the static
member's value. This problem can be reproduced as follows:

% cat t.cc
class A {
    typedef A type;
public:
    bool operator==(const type& other) { return true; }

    static const type INSTANCE;
};

const A A::INSTANCE;

int main() {
    A a;
    if (a == A::INSTANCE) {
        return -1;
    }
    return 0;
}
% g++ -g t.cc
% gdb -ex "start" -ex "p a" a.out

The fix is rather trivial - in cp_print_static_field(), should call
check_typedef() to get the static member's real type and use it to
check whether it's a struct or an array.

As Simon suggested, I've added a new test case to the testsuite
and am passing the original type, not the real type, as argument
to function val_print().

Re-tested on both aarch64-linux-gnu and amd64-linux-gnu. No regressions.
---
 gdb/ChangeLog                                 |    6 ++++
 gdb/cp-valprint.c                             |    8 +++---
 gdb/testsuite/ChangeLog                       |    5 +++
 gdb/testsuite/gdb.cp/static-typedef-print.cc  |   34 +++++++++++++++++++++++
 gdb/testsuite/gdb.cp/static-typedef-print.exp |   37 +++++++++++++++++++++++++
 5 files changed, 86 insertions(+), 4 deletions(-)
 create mode 100644 gdb/testsuite/gdb.cp/static-typedef-print.cc
 create mode 100644 gdb/testsuite/gdb.cp/static-typedef-print.exp

-- 
1.7.1

Comments

Simon Marchi March 27, 2018, 3:28 a.m. | #1
On 2018-03-26 17:54, Weimin Pan wrote:
> @@ -658,15 +659,14 @@ cp_print_static_field (struct type *type,

>        addr = value_address (val);

>        obstack_grow (&dont_print_statmem_obstack, (char *) &addr,

>  		    sizeof (CORE_ADDR));

> -      type = check_typedef (type);

> -      cp_print_value_fields (type, value_enclosing_type (val),

> +      cp_print_value_fields (real_type, value_enclosing_type (val),


As discussed previously, here we should pass the original type.

Btw, if you now have push access to the git repo, you should add 
yourself in the "Write After Approval" section of the gdb/MAINTAINERS 
file.  This will help you make sure everything is set up correctly.  
Don't forget to include a ChangeLog entry for it and post the patch on 
the mailing list afterwards (mentioning that you have pushed it), you 
can inspire yourself from how people have done it in the past.

Simon
Weimin Pan March 27, 2018, 7:53 p.m. | #2
On 3/26/2018 8:28 PM, Simon Marchi wrote:
> On 2018-03-26 17:54, Weimin Pan wrote:

>> @@ -658,15 +659,14 @@ cp_print_static_field (struct type *type,

>>        addr = value_address (val);

>>        obstack_grow (&dont_print_statmem_obstack, (char *) &addr,

>>              sizeof (CORE_ADDR));

>> -      type = check_typedef (type);

>> -      cp_print_value_fields (type, value_enclosing_type (val),

>> +      cp_print_value_fields (real_type, value_enclosing_type (val),

>

> As discussed previously, here we should pass the original type.


Hi Simon,

OK, just made the change to pass the original type to 
cp_print_value_fields()
which in turn calls check_typedef() to get the real type.

>

> Btw, if you now have push access to the git repo, you should add 

> yourself in the "Write After Approval" section of the gdb/MAINTAINERS 

> file.  This will help you make sure everything is set up correctly.  

> Don't forget to include a ChangeLog entry for it and post the patch on 

> the mailing list afterwards (mentioning that you have pushed it), you 

> can inspire yourself from how people have done it in the past.


Is there any document or instructions that I can access to understand 
the whole process better?

Thanks,
Weimin

>

> Simon
Simon Marchi March 27, 2018, 8:48 p.m. | #3
On 2018-03-27 15:53, Weimin Pan wrote:
> On 3/26/2018 8:28 PM, Simon Marchi wrote:

>> On 2018-03-26 17:54, Weimin Pan wrote:

>>> @@ -658,15 +659,14 @@ cp_print_static_field (struct type *type,

>>>        addr = value_address (val);

>>>        obstack_grow (&dont_print_statmem_obstack, (char *) &addr,

>>>              sizeof (CORE_ADDR));

>>> -      type = check_typedef (type);

>>> -      cp_print_value_fields (type, value_enclosing_type (val),

>>> +      cp_print_value_fields (real_type, value_enclosing_type (val),

>> 

>> As discussed previously, here we should pass the original type.

> 

> Hi Simon,

> 

> OK, just made the change to pass the original type to 

> cp_print_value_fields()

> which in turn calls check_typedef() to get the real type.

> 

>> 

>> Btw, if you now have push access to the git repo, you should add 

>> yourself in the "Write After Approval" section of the gdb/MAINTAINERS 

>> file.  This will help you make sure everything is set up correctly.  

>> Don't forget to include a ChangeLog entry for it and post the patch on 

>> the mailing list afterwards (mentioning that you have pushed it), you 

>> can inspire yourself from how people have done it in the past.

> 

> Is there any document or instructions that I can access to understand

> the whole process better?


I am not sure there is such a document, but there isn't that much to the 
process.  We should probably have a little something on the wiki though, 
if there isn't already.

To setup your git repo, see here, in the section "Read-write git":

https://www.gnu.org/software/gdb/current/

The important part is using the ssh:// address.  After that, it's like 
any other git repo.  It will use the public key you provided while 
registering for your account.  In my local repo, I added it as a 
different remote with a special name (other than origin) to help prevent 
pushing things accidentally.  So, for example:

$ git remote add upstream ssh://sourceware.org/git/binutils-gdb.git

You can then check that your access work by doing

$ git fetch upstream

Then:

1. While on the master branch, make sure you only have the patch (or 
patches) you intend to push applied on top of upstream/master.
2. Make sure you inserted the ChangeLog entries in the actual ChangeLog 
files and amended your commit
3. Push with "git push upstream master:master"
4. Notify the mailing list that you have pushed the patch.

For the patch adding yourself as a write-after-approval maintainer, you 
can see how Pedro did it recently:

The commit: 
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=7eb2418fa4641c60f6713986de7d3a50fd7a22c0
The mailing list message: 
https://sourceware.org/ml/gdb-patches/2018-03/msg00391.html

Simon
Weimin Pan March 27, 2018, 10:03 p.m. | #4
On 3/27/2018 1:48 PM, Simon Marchi wrote:
> On 2018-03-27 15:53, Weimin Pan wrote:

>> On 3/26/2018 8:28 PM, Simon Marchi wrote:

>>> On 2018-03-26 17:54, Weimin Pan wrote:

>>>> @@ -658,15 +659,14 @@ cp_print_static_field (struct type *type,

>>>>        addr = value_address (val);

>>>>        obstack_grow (&dont_print_statmem_obstack, (char *) &addr,

>>>>              sizeof (CORE_ADDR));

>>>> -      type = check_typedef (type);

>>>> -      cp_print_value_fields (type, value_enclosing_type (val),

>>>> +      cp_print_value_fields (real_type, value_enclosing_type (val),

>>>

>>> As discussed previously, here we should pass the original type.

>>

>> Hi Simon,

>>

>> OK, just made the change to pass the original type to 

>> cp_print_value_fields()

>> which in turn calls check_typedef() to get the real type.

>>

>>>

>>> Btw, if you now have push access to the git repo, you should add 

>>> yourself in the "Write After Approval" section of the 

>>> gdb/MAINTAINERS file.  This will help you make sure everything is 

>>> set up correctly.  Don't forget to include a ChangeLog entry for it 

>>> and post the patch on the mailing list afterwards (mentioning that 

>>> you have pushed it), you can inspire yourself from how people have 

>>> done it in the past.

>>

>> Is there any document or instructions that I can access to understand

>> the whole process better?

>

> I am not sure there is such a document, but there isn't that much to 

> the process.  We should probably have a little something on the wiki 

> though, if there isn't already.

>

> To setup your git repo, see here, in the section "Read-write git":

>

> https://www.gnu.org/software/gdb/current/

>

> The important part is using the ssh:// address.  After that, it's like 

> any other git repo.  It will use the public key you provided while 

> registering for your account.  In my local repo, I added it as a 

> different remote with a special name (other than origin) to help 

> prevent pushing things accidentally.  So, for example:

>

> $ git remote add upstream ssh://sourceware.org/git/binutils-gdb.git

>

> You can then check that your access work by doing

>

> $ git fetch upstream

>

> Then:

>

> 1. While on the master branch, make sure you only have the patch (or 

> patches) you intend to push applied on top of upstream/master.

> 2. Make sure you inserted the ChangeLog entries in the actual 

> ChangeLog files and amended your commit

> 3. Push with "git push upstream master:master"

> 4. Notify the mailing list that you have pushed the patch.

>

> For the patch adding yourself as a write-after-approval maintainer, 

> you can see how Pedro did it recently:

>

> The commit: 

> https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=7eb2418fa4641c60f6713986de7d3a50fd7a22c0

> The mailing list message: 

> https://sourceware.org/ml/gdb-patches/2018-03/msg00391.html


Hi Simon,

Thanks very much for the detailed information. I will try to go through 
the process with either
this patch or the small task of getting rid of the 
lookup_minimal_symbol_and_objfile calls.

Weimin

>

> Simon

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d0a8dfd..9534225 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@ 
+2018-02-07  Weimin Pan  <weimin.pan@oracle.com>
+
+	PR gdb/16959
+	* cp-valprint.c: (cp_print_static_field) Fix infinite recursion when
+	printing static type.
+
 2018-01-24  Pedro Alves  <palves@redhat.com>
 
 	GCC PR libstdc++/83906
diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c
index 486653f..8b4df98 100644
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -633,7 +633,8 @@  cp_print_static_field (struct type *type,
       return;
     }
 
-  if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+  struct type *real_type = check_typedef (type);
+  if (TYPE_CODE (real_type) == TYPE_CODE_STRUCT)
     {
       CORE_ADDR *first_dont_print;
       CORE_ADDR addr;
@@ -658,15 +659,14 @@  cp_print_static_field (struct type *type,
       addr = value_address (val);
       obstack_grow (&dont_print_statmem_obstack, (char *) &addr,
 		    sizeof (CORE_ADDR));
-      type = check_typedef (type);
-      cp_print_value_fields (type, value_enclosing_type (val),
+      cp_print_value_fields (real_type, value_enclosing_type (val),
 			     value_embedded_offset (val), addr,
 			     stream, recurse, val,
 			     options, NULL, 1);
       return;
     }
 
-  if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+  if (TYPE_CODE (real_type) == TYPE_CODE_ARRAY)
     {
       struct type **first_dont_print;
       int i;
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0f02f4a..6849d5a 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@ 
+2018-03-20  Weimin Pan  <weimin.pan@oracle.com>
+
+	* gdb.cp/static-typedef-print.exp: New file.
+	* gdb.cp/static-typedef-print.cc: New file.
+
 2018-01-22  Pedro Alves  <palves@redhat.com>
 	    Sergio Durigan Junior  <sergiodj@redhat.com>
 
diff --git a/gdb/testsuite/gdb.cp/static-typedef-print.cc b/gdb/testsuite/gdb.cp/static-typedef-print.cc
new file mode 100644
index 0000000..5faff3e
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/static-typedef-print.cc
@@ -0,0 +1,34 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2018 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/>.  */
+
+class A {
+    typedef A type;
+public:
+    bool operator==(const type& other) { return true; }
+
+    static const type INSTANCE;
+};
+
+const A A::INSTANCE = {};
+
+int main() {
+    A a;
+    if (a == A::INSTANCE) {
+        return -1;
+    }
+    return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/static-typedef-print.exp b/gdb/testsuite/gdb.cp/static-typedef-print.exp
new file mode 100644
index 0000000..ff6756e
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/static-typedef-print.exp
@@ -0,0 +1,37 @@ 
+# Copyright 2018 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/>.
+
+if { [skip_cplus_tests] } { continue }
+
+standard_testfile .cc
+
+if [get_compiler_info "c++"] {
+    return -1
+}
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} {
+    return -1
+}
+
+clean_restart $testfile
+
+if ![runto_main] {
+    untested "could not run to main"
+    return -1
+}
+
+gdb_test "print a" \
+         "static INSTANCE = <same as static member of an already seen type>}}.*" \
+         "print static member"