2

enter code hereI am seeing segfaults in a strange part of my code, and after using valgrind, it seemed the problem was the destructor of a parent being called during construction of the child. This is strange, so fired up gdb and indeed, I see constructor of child object being called, constructor of parent being called, and then destructor of parent being called before child constructor has exited. I did a fresh build, saw the same thing.

I assume this is impossible, and something funny is going on, but I have no idea what that might be or how to use gdb to determine what it is. Valgrind just tells me at a later point, when I try to use the parent object that I'm doing an invalid read because the relevant memory was deleted during construction of the child!

It's hard to break out the offending code to give a working example, but I can try to provide any other details that would be helpful. Using gcc 4.7.2.

* Edit * Here's a sketch of the inheritance chain:

class MKTimer: public MKSelfRegistrar<MKTimer>, public MKMakeable1<std::string>, public MKObject, public Timer;

MKObject is the offending parent.

MKTimer(const std::string& timer): Timer(timer) {}

MKObject() { some stuff here that doesn't seem relevant }

* Further Edit * I'll also mention that there are no explicit calls to delete and the gdb backtrace shows the call immediately above the parent destructor is the child constructor, so I don't think it's some other piece of code cleaning it up somehow.

pythonic metaphor
  • 10,296
  • 18
  • 68
  • 110
  • I don't suppose there's anything in that parent constructor that works out to `delete this`? – dlf Apr 24 '14 at 17:07
  • 1
    Are you sure the child contructor is called before the parent constructor? – Vincent Hubert Apr 24 '14 at 17:07
  • Can you share only the constructors and destructors, as well as the inheritance chain? – Deduplicator Apr 24 '14 at 17:10
  • Are you sure it is the same object? You may have an implicit temporary object built and destructed. Can you check that this is the same? – Vincent Hubert Apr 24 '14 at 17:10
  • @VincentHubert I mean gdb breaks on the line number of the child constructor, then starts executing the constructor of the parent objects (including the one that gets deleted), not the body of the constructor of the child – pythonic metaphor Apr 24 '14 at 17:10
  • @VincentHubert What I see is the break on the child with `this` at address x, the break on the parent with `this` at x+8 (which looks right to me). I can `up` and see the `this` pointer of the child is x, and then the destructor is called with the same `this` pointers again, so that seems to check out – pythonic metaphor Apr 24 '14 at 17:12
  • If you are able to break inside the destructor, why don't you check the call stack to find out what line is calling it? I'm not familiar with gdb, but assuming that it should have this feature. – Kirinyale Apr 24 '14 at 17:15
  • It looks that you have a temporary object being built. – Vincent Hubert Apr 24 '14 at 17:15
  • The `this` pointers should be identical between parent and child, unless there's multiple inheritance involved. – Mark Ransom Apr 24 '14 at 17:16
  • @MarkRansom even though there are virtual functions? – pythonic metaphor Apr 24 '14 at 17:18
  • Your inheritance chain looks incorrect. First there's no virtual inheritance shown, second `MKTimer` appears to inherit from itself. – Mark Ransom Apr 24 '14 at 17:19
  • @MarkRansom fixed the inherited from itself. that was a typo. And I fixed my last comment, it wasn't virtual inheritance, just that one the parent classes, `MKObject`, has virtual functions – pythonic metaphor Apr 24 '14 at 17:20
  • Does your constructor do the (erroneous) call of another constructor? It is now legal in C++11 to have delegating constructors similar to Java, but it is not legal before C++11. See here: http://stackoverflow.com/questions/13961037/delegate-constructor-c – PaulMcKenzie Apr 24 '14 at 17:21
  • The sibling base clases after it could be the culprit instead of `MKObject`. BTW: Using `struct` would save you many `public` specifiers. – Deduplicator Apr 24 '14 at 17:25
  • @PaulMcKenzie AFAIK, no, although still looking through the code – pythonic metaphor Apr 24 '14 at 17:26
  • I would start by looking at `MKSelfRegistrar`. Based on the name, that base ctor is probably adding `this` to some static list somewhere. And maybe some other entity (one of the other base classes?) executes a cleanup on that list and `delete`s things it considers unnecessary; perhaps objects with inconsistent state like the one you're only halfway through constructing. – dlf Apr 24 '14 at 17:29
  • MKSelfRegistrar actually does something else that's pretty innocuous. I am looking at Makeable1 though. However, whatever any of it does, there are no 'deletes' in the code, so I don't see the object ever getting explicitly deleted. – pythonic metaphor Apr 24 '14 at 17:30
  • @pythonicmetaphor - Are you able to get a call stack on the delete that is occurring? If so, where does the deletion originate? – PaulMcKenzie Apr 24 '14 at 17:37
  • @PaulMcKenzie I see at the lowest level Parent::~Parent and then right above it Child::Child. This is in a debug build with no optimizations – pythonic metaphor Apr 24 '14 at 17:39

1 Answers1

2

There is only one reason for a child class constructor to call the destructor of its base class: failure.

So, your problem is likely due to an exception that is thrown somewhere in the construction of the child. This causes the stack to be unwound and all objects are destructed which have already been constructed. Since it is the constructor of the child class that calls the constructors of all its parents, it is also the constructor of the child that calls its destructor during exception cleanup.

However, don't give too much weight to the source code line that is produced by gdb, it may be wrong. So the bug may still be something wildly different.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • yes, I think that is the problem. The construction was failing, the exception was being caught somewhere, but a pointer to the class has been registered somewhere and not removed. – pythonic metaphor Apr 24 '14 at 17:51