[patch/testsuite/c++] test script for PR c++/186

Michael Elizabeth Chastain mec.gnu@mindspring.com
Sun Nov 23 22:05:00 GMT 2003


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  <mec.gnu@mindspring.com>

	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"
    }
}



More information about the Gdb-patches mailing list