From: tarbox@cat.rpi.edu (Glenn Tarbox)
Subject: (none)
Organization: GNUs Not Usenet
Distribution: gnu
Date: Fri, 21 Aug 1992 17:07:32 GMT

Hello,

This is what I hope is a complete bug report on a problem with gdb
which I know existed in 4.4 and is still with us in 4.6.

First the necessary background.  The computer sytem is a Sun Sparc
running 4.1.1.  I used the gcc-2.2.2 compiler to compile gdb and the
test program included.  When gdb is compiled using suns cc compiler,
the problem persists.

To compile the test program code included I used the following:

g++ -ggdb3 -o testgdb testgdb.cc

Simply stated, the problem is that (using g++) when passing an object
by value to a subroutine, the debugger gets the address of the object
passed into the subroutine wrong.  Therefore, when looking at that
object, it has garbage inside.

The object does get passed correctly, however, as the test code which I
wrote illustrates.

First, the code which illustrates the problem.  The line numbers correspond
to those provided by gdb.  At the end of this note, this file is provided
without the numbers to facilitate testing at your site.

1	#include <stdio.h>
2	
3	class mytestclass{
4	  int first, second, third, fourth;;
5	public:
6	  mytestclass(){first=second=third=fourth=1;}
7	  mytestclass(mytestclass &inarg);
8	  void printout();
9	};
10	
11	mytestclass::mytestclass(mytestclass &inarg)
12	{
13	  (*this)=inarg;
14	  fprintf(stderr," in the copy constructor\n");
15	  printout();
16	}
17	
18	void mytestclass::printout()
19	{
20	  fprintf(stderr," variables = %d, %d, %d, %d\n",first,second,third,fourth);
21	  fprintf(stderr," this = %X\n",(int)this);
22	}
23	
24	void testsubroutine(mytestclass subarg);
25	
26	main()
27	{
28	  mytestclass testone;
29	
30	  mytestclass testtwo(testone);
31	
32	  testsubroutine(testtwo);
33	}
34	
35	void testsubroutine(mytestclass subarg)
36	{
37	  fprintf(stderr," in the subroutine\n");
38	  subarg.printout();
39	}

When this code is run, the following output is produced:

 in the copy constructor
 variables = 1, 1, 1, 1
 this = F7FFF850
 in the copy constructor
 variables = 1, 1, 1, 1
 this = F7FFF840
 in the subroutine
 variables = 1, 1, 1, 1
 this = F7FFF840

What this code shows is that in the copy constructor, the same object is
being initialized as is eventually being passed to the testsubroutine
subroutine.  The code works as we expect it would.

But, the issue is:  What happens to gdb when looking at an object which
has been passed by value to a subroutine and when a copy constructor
is provided?  Here is a gdb session which explores that question.

NOTE:  I have annotated this session with comments after the gt>
symbol

Current directory is /home/a/tarbox/testgdb/
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.6, Copyright 1992 Free Software Foundation, Inc...
(gdb) Breakpoint 1 at 0x2320: file testgdb.cc, line 14.
(gdb) Breakpoint 2 at 0x2404: file testgdb.cc, line 32.
(gdb) Breakpoint 3 at 0x2454: file testgdb.cc, line 37.
(gdb) r
Starting program: /home/a/tarbox/testgdb/testgdb 

Breakpoint 1, mytestclass::mytestclass (this=0xf7fff850, inarg=@0xf7fff860)
    at testgdb.cc:14
(gdb) p this
$1 = (struct mytestclass *) 0xf7fff850
(gdb) c
Continuing.
 in the copy constructor
 variables = 1, 1, 1, 1
 this = F7FFF850

Breakpoint 2, main () at testgdb.cc:32
(gdb) p &testtwo
$2 = (struct mytestclass *) 0xf7fff850
(gdb) p testtwo
$3 = {first = 1, second = 1, third = 1, fourth = 1}
(gdb) c
Continuing.

gt> We see here that the "this" pointer printed by fprintf in the
gt> copy constructor is the same as what gdb sees for testtwo 
gt> after it is created in main().  This is how we expect the copy
gt> constructor to work.

Breakpoint 1, mytestclass::mytestclass (this=0xf7fff840, inarg=@0xf7fff850)
    at testgdb.cc:14
(gdb) p this
$4 = (struct mytestclass *) 0xf7fff840
(gdb) c
Continuing.
 in the copy constructor
 variables = 1, 1, 1, 1
 this = F7FFF840

gt> Here, in the copy constructor, which is being called because the
gt> argument to testsubroutine is being passed by value, we see that
gt> "this" as printed by gdb and printed by fprintf correspond.

Breakpoint 3, testsubroutine (subarg={first = 4194437, second = 8292, 
      third = 8296, fourth = 0}) at testgdb.cc:37
(gdb) p &subarg
$5 = (struct mytestclass *) 0xf7fff7c8
(gdb) p subarg
$6 = {first = 4194437, second = 8292, third = 8296, fourth = 0}
(gdb) c
Continuing.
 in the subroutine
 variables = 1, 1, 1, 1
 this = F7FFF840

>gt Here is the problem.  The address for subarg is different than the
gt> "this" in the copy constructor which created subarg.  However, the
gt> value F7FFF840 is what gdb had for "this" when in the copy constructor.
gt> The value for subarg used by gdb, 0xf7fff7c8, is wrong as indicated by
gt> value printed by fprintf for that object in printout().

Program exited normally.
(gdb) quit

So, the problem here is simple to state.  Somehow, when an object is
passed to a subroutine by value, and a copy constructor exists, gdb
evaluates an incorrect address to that object.

Thanks for you time,

-glenn

------------------------------------------------------------------------
Glenn Tarbox - tarbox@cat.rpi.edu   (518) 276-8367
New York State Center for Advanced Technology in Automation and Robotics
CII-8015, Rensselaer Polytechnic Institute, Troy, NY  12180-3590
------------------------------------------------------------------------

PS: Below is the program code without the numbers so you can take it
directly and play with it.

#include <stdio.h>

class mytestclass{
  int first, second, third, fourth;;
public:
  mytestclass(){first=second=third=fourth=1;}
  mytestclass(mytestclass &inarg);
  void printout();
};

mytestclass::mytestclass(mytestclass &inarg)
{
  (*this)=inarg;
  fprintf(stderr," in the copy constructor\n");
  printout();
}

void mytestclass::printout()
{
  fprintf(stderr," variables = %d, %d, %d, %d\n",first,second,third,fourth);
  fprintf(stderr," this = %X\n",(int)this);
}

void testsubroutine(mytestclass subarg);

main()
{
  mytestclass testone; // create a default object

  mytestclass testtwo(testone); // test the copy constructor

  testsubroutine(testtwo);
}

void testsubroutine(mytestclass subarg)
{
  fprintf(stderr," in the subroutine\n");
  subarg.printout(); // print the object passed by value
}

Newsgroups: gnu.gdb.bug