From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 470 invoked by alias); 23 Nov 2003 22:05:13 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 463 invoked from network); 23 Nov 2003 22:05:11 -0000 Received: from unknown (HELO blount.mail.mindspring.net) (207.69.200.226) by sources.redhat.com with SMTP; 23 Nov 2003 22:05:11 -0000 Received: from user-119a90a.biz.mindspring.com ([66.149.36.10] helo=berman.michael-chastain.com) by blount.mail.mindspring.net with esmtp (Exim 3.33 #1) id 1AO2Lo-00049Z-00 for gdb-patches@sources.redhat.com; Sun, 23 Nov 2003 17:05:04 -0500 Received: by berman.michael-chastain.com (Postfix, from userid 502) id 1F77C4B409; Sun, 23 Nov 2003 17:04:45 -0500 (EST) To: gdb-patches@sources.redhat.com Subject: [patch/testsuite/c++] test script for PR c++/186 Message-Id: <20031123220445.1F77C4B409@berman.michael-chastain.com> Date: Sun, 23 Nov 2003 22:05:00 -0000 From: mec.gnu@mindspring.com (Michael Elizabeth Chastain) X-SW-Source: 2003-11/txt/msg00502.txt.bz2 This is a new test script. It's for PR gdb/186: http://sources.redhat.com/gdb/bugs/186 gdb have problems with C++ casting Here is a summary of the code: class A; class B : public A; int main (void) { B beta, *beta_p; beta_p = β ... } // breakpoint here And here is a summary of the *.exp file: (gdb) break "breakpoint here" (gdb) print beta ... okay ... (gdb) print * beta_p ... gdb prints bogus data ... The issue is that the user is accessing a destroyed object through a pointer. Because the object has been destroyed, its vptr has been degraded to its most primitive base class. gdb gets confused and prints incorrect data, which is always wrong. Testing: I tested this on native i686-pc-linux-gnu with: gcc 2.95.3 -gdwarf-2 gcc 2.95.3 -gstabs+ gcc 3.3.2 -gdwarf-2 gcc 3.3.2 -gstabs+ The results are all PASS and KFAIL, with no FAIL. I'll put this up for a few days for comment, especially from David C. Then I'll commit it. Michael C === 2003-11-23 Michael Chastain New test case for PR c++/186. * gdb.cp/gdb186.cc: New file. * gdb.cp/gdb186.exp: New file. === /* This testcase is part of GDB, the GNU debugger. Copyright 2003 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Please email any bugs, comments, and/or additions to this file to: bug-gdb@prep.ai.mit.edu */ struct A { virtual ~A (); int a1; }; A::~A() { ; } struct B : public A { virtual ~B (); int b1; int b2; }; B::~B() { ; } void marker1 (A *) { ; } int main (void) { A *alpha_p; B beta, *beta_p; beta.a1 = 100; beta.b1 = 200; beta.b2 = 201; alpha_p = β beta_p = (B *) alpha_p; marker1 (alpha_p); marker1 (beta_p); return 0; // marker return 0 } // marker close brace === # Copyright 2003 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 2 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, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Test for PR gdb/186. # # This is a problem with C++ casting on a dead object. The object's # type (its vptr) has been degraded by its destructors. if $tracelevel then { strace $tracelevel } if { [skip_cplus_tests] } { continue } set prms_id 0 set bug_id 0 set testfile "gdb186" set srcfile ${testfile}.cc set binfile ${objdir}/${subdir}/${testfile} if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." } gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} if ![runto_main] then { perror "couldn't run to main" continue } gdb_test "break [gdb_get_line_number "marker return 0"]" \ "Breakpoint.*at.* file .*" "" gdb_test "continue" "Breakpoint .* at .*" "" # This part should be simple and good. gdb_test "print beta" \ "= {.*a1 = 100.*b1 = 200.*b2 = 201}" \ "print beta at marker return 0" gdb_test "print * beta_p" \ "= {.*a1 = 100.*b1 = 200.*b2 = 201}" \ "print * beta_p at marker return 0" gdb_test "print * (B *) alpha_p" \ "= {.*a1 = 100.*b1 = 200.*b2 = 201}" \ "print * (B *) alpha_p at marker return 0" gdb_test "print * alpha_p" \ "= {.*a1 = 100.*}" \ "print * alpha_p at marker return 0" # All that again, at the close brace. # # This is where the real problem happens. "beta" has been destroyed! # The gcc code for B::~B changes the type (the vptr) of "beta" from # "B" to "A" so that B::~B can call A::~A. Every C++ compiler has to # do something like this, in case A::~A calls a virtual function. # # It would also be legal for a C++ compiler to put some kind of sentinel # value in beta.vptr so that it's not even an "A" any more. But I am # not seeing that with gcc. # # So, the user is trying to print a structure of type "B", but there is # only an "A" in memory, and the user might not even realize that. gdb_test "break [gdb_get_line_number "marker close brace"]" \ "Breakpoint.*at.* file .*" "" gdb_test "continue" "Breakpoint .* at .*" "" gdb_test_multiple "print beta" "print beta at marker close brace" { -re "= {.*a1 = 100.*b1 = 200.*b2 = 201}\r\n$gdb_prompt " { # the data fields should still be okay even though beta is dead pass "print beta at marker close brace" } } # "* beta_p" has static type "B", but there is probably only an "A" # in memory after B::~B does its thing. The user may not realize # this so gdb should be careful to be informative here. # # TODO: add another PASS case for this depending on what David C # thinks the correct output should be. gdb_test_multiple "print * beta_p" "print * beta_p at marker close brace" { -re "= {.*a1 = 100.*b1 = 200.*b2 = 201}\r\n$gdb_prompt $" { # This is not happening, but it would be okay. pass "print * beta_p at marker close brace" } -re "= {.*a1 = 100}\r\n$gdb_prompt $" { # This is not happening, but it would be okay, # although a little surprising. pass "print * beta_p at marker close brace" } -re "= {.*a1 = 100.*b1 = .*b2 = .*}\r\n$gdb_prompt $" { # gcc 2.95.3 -gstabs+ # gcc 3.3.2 -gdwarf-2 # gcc 3.3.2 -gstabs+ # Someone might argue that gdb is not buggy here but I think it is. kfail "gdb/186" "print * beta_p at marker close brace #1" } -re "= {.*a1 = .*b1 = .*b2 = .*}\r\n$gdb_prompt $" { # gcc 2.95.3 -gdwarf-2 # gdb does not even get the value of a1 right! kfail "gdb/186" "print * beta_p at marker close brace #2" } } # Another way to pose the same question. gdb_test_multiple "print * (B *) alpha_p " "print * (B *) alpha_p at marker close brace" { -re "= {.*a1 = 100.*b1 = 200.*b2 = 201}\r\n$gdb_prompt $" { # This is not happening, but it would be okay. pass "print * (B *) alpha_p at marker close brace" } -re "= {.*a1 = 100}\r\n$gdb_prompt $" { # This is not happening, but it would be okay, # although a little surprising. pass "print * (B *) alpha_p at marker close brace" } -re "= {.*a1 = 100.*b1 = .*b2 = .*}\r\n$gdb_prompt $" { # gcc 2.95.3 -gstabs+ # gcc 3.3.2 -gdwarf-2 # gcc 3.3.2 -gstabs+ # Someone might argue that gdb is not buggy here but I think it is. kfail "gdb/186" "print * (B *) alpha_p at marker close brace #1" } -re "= {.*a1 = .*b1 = .*b2 = .*}\r\n$gdb_prompt $" { # gcc 2.95.3 -gdwarf-2 # gdb does not even get the value of a1 right! kfail "gdb/186" "print * (B *) alpha_p at marker close brace #2" } } # This should work better, as long as beta is still an "A" at least. gdb_test_multiple "print * alpha_p" "print * alpha_p at marker close brace" { -re "= {.*a1 = 100.*b1 = 200.*b2 = 201}\r\n$gdb_prompt $" { # this should not happen but if it did, it would be okay pass "print * alpha_p at marker close brace" } -re "= {.*a1 = .*b1 = .*b2 = .*}\r\n$gdb_prompt $" { # if gdb prints any values and they are WRONG, that is not okay kfail "gdb/186" "print * alpha_p at marker close brace #1" } -re "= {.*a1 = 100.*}\r\n$gdb_prompt $" { # gcc 2.95.3 -gstabs+ # gcc 3.3.2 -gdwarf-2 # gcc 3.3.2 -gstabs+ # this is okay pass "print * alpha_p at marker close brace" } -re "= {.*a1 = .*}\r\n$gdb_prompt $" { # gcc 2.95.3 -gdwarf-2 kfail "gdb/186" "print * alpha_p at marker close brace #2" } }