Bug 9170 - Unable to locate constructors with forward-declared classes
Summary: Unable to locate constructors with forward-declared classes
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.4
: P3 normal
Target Milestone: 7.2
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-01-07 21:48 UTC by Thomas Richter
Modified: 2010-03-13 02:47 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Thomas Richter 2006-01-07 21:48:01 UTC
[Converted from Gnats 2065]

gdb fails to resolve the address of class constructors correctly if the class declaration (instead of its definition) is found first in the symbol file.

Release:
6.4

Environment:
i686-pc-linux-gnu

How-To-Repeat:
If a source file contains a forward declaration of a class, and this file is compiled first, then g++ inserts a "typedef" symbol into the debugging output. If now a breakpoint is set at the constructor of this class, this typedef is resolved instead of the full name, giving it an address of zero. If gdb is requested to list the constructor, it crashes with a segfault. Similarly, if a breakpoint is inserted at the constructor, setting the breakpoint fails because it is thought of to be at address zero. 

Thus, this bug is hard to reproduce because it depends on the layout of the object file whether the mentioned problem appears. See the fix below, though.
Comment 1 Thomas Richter 2006-01-07 21:48:01 UTC
Fix:
Replace gdb/symtab.c, lines 1789ff by the following:

	  if (SYMBOL_DOMAIN (sym) == domain
	      && (linkage_name != NULL
		  ? strcmp (SYMBOL_LINKAGE_NAME (sym), linkage_name) == 0 : 1)) { /* FIX THOR */
	    if (domain != VAR_DOMAIN || sym->aclass != LOC_TYPEDEF) /* Must *NOT* use type forwards here */
	      return sym;
	  } /* FIX THOR end */

This adds an additional test for forward declarations and avoids to return them as valid symbol resolutions.
Comment 2 Tom Tromey 2010-02-10 22:32:09 UTC
I tried to reproduce this but couldn't.
I tried compiling two files like so:

== main.cc
class K;

extern K *getk();

int main () {
  K* k = getk();

  return 0;
}

== k.ccclass K {
public:
  K ();

  int z;
};

K::K () {
  z = 25;
}

K *getk() {
  return new K;
}


I figured this was most likely to get the forward declaration read in
first.

On trunk I get weird behavior, e.g., "break K::K" does nothing at all.
This doesn't sound like your bug, though.  Maybe the crash has been fixed.

It would be most helpful if you had a simple way to reproduce this.

Comment 3 Thomas Richter 2010-02-16 23:43:59 UTC
(In reply to comment #2)
> I tried to reproduce this but couldn't.
> I tried compiling two files like so:
> 
> == main.cc
> class K;
> 
> extern K *getk();
> 
> int main () {
>   K* k = getk();
> 
>   return 0;
> }
> 
> == k.ccclass K {
> public:
>   K ();
> 
>   int z;
> };
> 
> K::K () {
>   z = 25;
> }
> 
> K *getk() {
>   return new K;
> }
> 
> 
> I figured this was most likely to get the forward declaration read in
> first.
> 
> On trunk I get weird behavior, e.g., "break K::K" does nothing at all.
> This doesn't sound like your bug, though.  Maybe the crash has been fixed.
> 
> It would be most helpful if you had a simple way to reproduce this.

What you see here is indeed another bug related to constructors, however, one
that isn't fixed by the code above. With the present gdb, I cannot reproduce the
2006 bug anymore, but I can reproduce here (and on my own sources) that setting
a breakpoint in a constructor does not work, as you did above.

Suggestion: Close the old bug, open a new concerning setting breakpoints on
constructors.


Comment 4 Pedro Alves 2010-02-17 00:09:50 UTC
Hmmm, the bug the OP has described look very much like PR10966 and PR8166
to me.

Notice the last command on:
 http://sourceware.org/ml/gdb/2010-02/msg00090.html

" (gdb) p Foo::Foo
 Cannot look up value of a typedef "

His pseudo-patch doesn't have context to know better, so I can't tell
if its essentially the same as the FUNCTIONS_DOMAIN suggestion
on PR10966, or a better fix (it may well be, I may very well misdiagnosed
the real issue, as I didn't bother with it, given that getting rid
of physname gets rid of the bug).
Comment 5 Thomas Richter 2010-02-17 18:20:00 UTC
Played again with it. The trouble becomes at least more obvious if the class in
question has multiple constructors. Here's how to reproduce - and while gdb
certainly doesn't crash anymore, it still tries to set the breakpoint at address
0x0:

Enter the following as class.cpp:

/* snip */
class A {
  int  x;
  bool b;
  A   *p;
public:
  A(int i)
    : x(i), b(false), p(0)
  { };
  A(int i,bool a)
    : x(i), b(a), p(0)
  { };
  A(int i,A *next)
    : x(i), p(next)
  { }
  
  ~A()
  {
    if (p)
      p->inc();
  }
  void inc()
  {
    x++;
  }
};

A *getA(int x)
{
  A a(1);
  return new A(x,&a);
}

void dispose(A *a)
{
  delete a;
}
/* snip */

Enter the following as main.cpp:
/* snip */
extern class A *getA(int x);
extern void dispose(class A *);

int main(int argc,char **argv)
{
  class A *ap = getA(1);

  dispose(ap);
}
/* snip */

Compile with:
g++ -c -ggdb3 -O0 -o class.o class.cpp
g++ -c -ggdb3 -O0 -o main.o main.cpp

Link with:
g++ -o a.out class.o main.o

Run the debugger with:
gdb a.out

Then try:
break A::A

The result of which is:
[0] cancel
[1] all
?HERE
?HERE
?HERE

Then enter 1. The result is:
Note: breakpoint -1 (disabled) also set at pc 0x0.
Breakpoint 1 at 0x0
Note: breakpoints -1 (disabled) and 1 also set at pc 0x0.
Breakpoint 2 at 0x0
Note: breakpoints -1 (disabled), 1 and 2 also set at pc 0x0.
Breakpoint 3 at 0x0
warning: Multiple breakpoints were set.
Use the "delete" command to delete unwanted breakpoints.

Also known as "nonsense". With the patch in question, the situation does in so
far get better as errors are no longer printed, but the breakpoint nevertheless
doesn't work - or is set at the wrong place.

Part of the problem might be that g++ generates multiple routines for the same
constructor (i.e. one constructor is expanded into several assembly routines
depending on whether the object is allocated on the heap or the stack), and
apparently, gdb sets the breakpoint at the wrong place.

Unfortunately, this is indeed a long standing bug, I've never been able to debug
constructors successfully with any gdb version I have seen so far. The onyl
workaround I know is to add a dummy function to constructors and set a
breakpoint in this dummy....

So long,
Thomas
Comment 6 Tom Tromey 2010-02-17 18:25:52 UTC
Yeah, that behavior is what is seen in those other PRs.
We do have a patch for this bug, but it won't go in until after 7.1.
The patch will go in pretty soon after 7.1 branches, so sometime
very soon you should be able to use CVS gdb to solve this.
Comment 7 Tom Tromey 2010-03-13 02:47:17 UTC
I believe this is fixed in cvs now.