5

I have an interesting problem in one of my C++ programs. Apperantly the vtable of one of my classes is/becomes messed up during program execution. In a gdb session I found out that if I call a method of the object directly it succeeds, but if I use a pointer or reference I end up in the destructor of a completely unrelated class which isn't going to be instantiated anytime soon. Without the this-Pointer changing of course.

Assuming my observations are correct, how do I watch the vtable of an object in gdb? I'm on Linux using gcc, my gdb version is GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08.

Raphael R.
  • 23,524
  • 1
  • 22
  • 18
  • I'm not 100% on this, so I won't post it as an answer, but it should be enough to look at `((void*)this)-1` (a pointer length *before* `this`) to get a pointer to a (0-terminated?) array of pointers to the actual functions. They won't carry method names or anything, but that's really all the vtable is. – Blindy Oct 06 '11 at 17:43
  • Did you profile your code with Valgrind or any such similar tool? – Alok Save Oct 06 '11 at 17:44
  • How do you know you end up in a different function? Are you debugging or outputting something? – Luchian Grigore Oct 06 '11 at 17:49
  • As @Als said, use `valgrind`. You generally can't modify the vtable, because is is in protected memory, but it's quite possible to mess up the vptr, so that it points to something else. – James Kanze Oct 06 '11 at 17:50
  • I'm debugging. I set a breakpoint inside the virtual function. It gets hit if I call through the object, but not if I call through a pointer. -I am going to try valgrind now, thanks for the tip. – Raphael R. Oct 06 '11 at 17:51

2 Answers2

4

You can use the -fdump-class-hierarchy option of gcc which will give you the vtable information, however the output can be very verbose and hard to read.

For instance, given the following trivial classes:

class Base {                                                                            
    public:                                                                             
        virtual int method() = 0;                                                       
};                                                                                      

class Derived : public Base {                                                           
    public:                                                                             
        int method() {                                                                  
            return 10;                                                                  
        }                                                                               
};  

the relevant output is

Vtable for Base
Base::_ZTV4Base: 3u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI4Base)
16    (int (*)(...))__cxa_pure_virtual

Class Base
   size=8 align=8
   base size=8 base align=8
Base (0x7f14c308ccc0) 0 nearly-empty
    vptr=((& Base::_ZTV4Base) + 16u)

Vtable for Derived
Derived::_ZTV7Derived: 3u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI7Derived)
16    (int (*)(...))Derived::method

Class Derived
   size=8 align=8
   base size=8 base align=8
Derived (0x7f14c2ee7208) 0 nearly-empty
    vptr=((& Derived::_ZTV7Derived) + 16u)
  Base (0x7f14c308cd20) 0 nearly-empty
      primary-for Derived (0x7f14c2ee7208)

This should give you an idea which address ranges to expect during debuggng etc.

bbtrb
  • 4,065
  • 2
  • 25
  • 30
  • This, and the snippet at http://stackoverflow.com/questions/6191678/printc-vtables-using-gdb was exactly what I needed. Turns out that a 'clever' function doesn't play nice with objects with virtual methods. Thanks. – Raphael R. Oct 07 '11 at 16:48
  • I'd be interested in the "clever" function. I like to break things :) – bbtrb Oct 07 '11 at 17:19
0

Unless you're hacking, I doubt your vtable gets messed up. Are you calling the virtual function from the costructor?

It might also be that the debugger is messing with you. Compiling with optimization, you might get the same address for functions that do the same thing, as to not have duplicated code. I ran into this under Windows, where Visual Studio was also jumping in different functions that actually did the same thing. Try outputting something instead of walking through the code with the debugger... This might be the cause.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    Note for posterity: vtables can get messed up in a variety of ways. "Hacking" that attacks the vtable typically just attacks the sort of bugs that the OP is probably trying to squash. A good rule of thumb is to suspect a buffer overrun, or a use-after-free. – Wug Oct 27 '14 at 19:31