Original question:
Why is the this pointer 0 in a VS c++ release build?
When breaking in a Visual Studio 2008 SP1 release build with the /Zi (Compiler: Debug Information Format - Program Database) and /DEBUG (Linker: Generate Debug Info, yes) options, why are 'this'-pointers always 0x00000000?
EDIT: Rephrased question:
My original question was quite unclear, sorry for that. When using the Visual Studio 2008 debugger to step through a program I can see all variables, except the local object's member variables. This is probably cause the debugger derives these from the this pointer, but VS always says it's 0x00000000, so it cannot derive the current object's member variables (it does not know the memory position of the object)
When loading a megadump (Like a Windows minidump, but containing the entire memory space of the process), I can look at all my local variables (defined in the function) and entire tree-structures on the heap even I have pointers to.
For example: when breaking in A::foo() in Release mode
'this' will have value 0x00000000
'f_' will show garbage
Somehow this information needs to be available to the process. Is this a missing feature in VS2008? Any other debugger that does handle this properly?
class A
{
void foo() { /*break here*/ }
int f_;
};
As some others have mentioned, compiling in Release mode makes certain optimizations (especially eliminating the use of ebp/rbp as a frame pointer) that break assumptions on which the debugger relies for figuring out your local variables. However, knowing why it happens isn't very helpful for debugging your program!
Here's a way you can work around it: at the very beginning of a method call (breaking on the first line of the function, not the opening brace), the this
pointer will always be found in a specific register (ecx on 32-bit systems or rcx on 64-bit systems). The debugger knows that and so you should be able to see the value of this
right at the start of your method call. You can then copy the address from the Value column and watch that specifically (as (MyObject *)0x003f00f0
or whatever), which will allow you to see into this
later in the method.
If that's not good enough (for example, because you only want to stop when a bug manifests itself, which is a very small percentage of the time the given method is called), you can try this slightly more advanced (and less reliable) trick. Usually, the this
pointer is taken out of ecx/rcx very early in a function call, because that is a "caller-saves" register, meaning that its value may be clobbered and not restored by function calls your method makes (it's also needed for some instructions that can only use that register for their operand, like REP* and some of the shift instructions). However, if your method uses the this
pointer a lot (including the implicit use of referring to member variables or calling virtual member functions), the compiler will probably have saved this
in another register, a "callee-saves" register (meaning that any function that clobbers it must restore it before returning).
The practical upshot of this is that, in your watch window, you can try looking at (MyObject *) ebp
, (MyObject *) esi
, and so on with other registers, until you find that you're looking at a pointer that is probably the correct one (because the member variables line up with your expectation of the contents of this
at the time of your breakpoint). On x86, the calle-saved registers are ebp, esi, edi, and ebx. On x86-64, they are rbp, rsi, rdi, rbx, r12, r13, r14, and r15. If you don't want to search all those, you could always try looking at the disassembly of your function prologue to see what ecx (or rcx) is being copied into.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With