views:

202

answers:

7

I've got a strange problem here. Assume that I have a class with some virtual methods. Under a certain circumstances an instance of this class should call one of those methods. Most of the time no problems occur on that stage, but sometimes it turns out that virtual method cannot be called, because the pointer to that method is NULL (as shown in VS), so memory access violation exception occurs. How could that happen?

Application is pretty large and complicated, so I don't really know what low-level steps lead to this situation. Posting raw code wouldn't be useful.

UPD: Ok, I see that my presentation of the problem is rather indefinite, so schematically code looks like

void MyClass::FirstMethod() const { /* Do stuff */ }
void MyClass::SecondMethod() const
{
    // This is where exception occurs, 
    // description of this method during runtime in VS looks like 0x000000
    FirstMethod(); 
}

No constructors or destructors involved.

+1  A: 

One scenario this could happen in is if you tried to call a pure virtual method in a destructor or constructor. At this point the virtual table pointer for the method may not be initialized causing a crash.

JaredPar
Hm, I just realized that method is not even virtual. It is not called in constructor or destructor, it's just an accessor of a field, which is called during screen redraw procedure.
Tony
@Tony: based on the comment you just made it sounds like you're calling the method with an object pointer that's `NULL` (or otherwise invalid). A compiler will be able to make the function call with a `NULL` object pointer since it's a non-virtual call that can be statically resolved at compile/link time. However, when the function tries to actually access a class member, it'll try to do so through the invalid object pointer.
Michael Burr
+3  A: 

Possibly you're calling the function (directly or indirectly) from a constructor of a base class which itself doesn't have that function.

Possibly there's a broken cast somewhere (such as a reinterpret_cast of a pointer when there's multiple inheritance involved) and you're looking at the vtable for the wrong class.

Possibly (but unlikely) you have somehow trashed the vtable.

Is the pointer to the function null just for this object, or for all other objects of the same type? If the former, then the vtable pointer is broken, and you're looking in the wrong place. If the latter, then the vtable itself is broken.

Steve Jessop
agrred. reinterpret_cast will definitely ruin the vtable in multiple inheritance scenario.
YeenFei
+2  A: 

Heap corruption is a likely candidate. The v-table pointer in the object is vulnerable, it is usually the first field in the object. A buffer overflow for some kind of other object that happens to be adjacent to the object will wipe the v-table pointer. The call to a virtual method, often much later, will blow.

Another classic case is having a bad "this" pointer, usually NULL or a low value. That happens when the object reference on which you call the method is bad. The method will run as usual but blow up as soon as it tries to access a class member. Again, heap corruption or using a pointer that was deleted will cause this. Good luck debugging this, it is never easy.

Hans Passant
The problem is that I can't debug this. Strange, but exception does not occur when I run application in DEBUG mode in VS.
Tony
Yes, heap corruption behaves that way. It is much less likely that the v-table pointer gets corrupted, a debug allocator tends to put guards around the block. VS has <crtdbg.h> to help you locate these kind of problems.
Hans Passant
@nobugz, thanks, it seems that object reference is damaged. I can't figure out how it happens exactly, but re-writing some code related to obtaining this reference seems to fix this bug.
Tony
+1  A: 

Is it possible the "this" pointer is getting deleted during SecondMethod's processing?

Another possibility is that SecondMethod is actually being called with an invalid pointer right up front, and that it just happens to work (by undefined behavior) up to the nested function call which then fails. If you're able to add print code, check to see if "this" and/or other pointers being used is something like 0xcdcdcdcd or 0xfdfdfdfd at various points during execution of those methods. Those values are (I believe) used by VS on memory alloc/dealloc, which may be why it works when compiled in debug mode.

Mark B
A: 

What you are most likely seeing is a side-effect of the actual problem. Most likely heap or memory corruption, or referencing a previously freed object or null pointer.

If you can consistently have it crash at the same place and can figure out where the null pointer is being loaded from then I suggest using the debugger and put a breakpoint on 'write' at that memory location, once the breakpoint is trigerred then most likely you are viewing the code that has actually caused the corruption.

KPexEA
I just noticed the comment (in nobugz response) about debug mode not crashing. You could still debug this in release mode but that will be a bit trickier, but still do-able depending on how good you are with a debugger and symbols tables.
KPexEA
A: 

If memory access violation happens only when Studio fails to show method address, then it could be caused by missing debug information. You probably are debugging the code compiled with release (non-debug) compiler/linker flags.

Try to enable some debug info in C++ properties of project, rebuild and restart debugger. If it will help, you will see all normal traceable things like stack, variables etc.

RocketSurgeon
A: 

If your this pointer is NULL, corruption is unlikely. Unless you're zeroing memory you shouldn't have.

You didn't say if you're debugging Debug (not optimized) or Release (optimized) build. Typically, in Release build optimizer will remove this pointer if it is not needed. So, if you're debugging optimized build, seeing this pointer as 0 doesn't mean anything. You have to rely on the deassembly to tell you what's going on. Try turning off optimization in your Release build if you cannot reproduce the problem in Debug build. When debugging optimized build, you're debugging assembly not C++.

If you're already debugging a non-optimized build, make sure you have a clean rebuild before spending too much time debugging corrupted images. Debug builds are typically linked incrementally and incremental linker are known to produce problems like this. If you're running Debug build with clean build and still couldn't figure out what went wrong, post the stack dump and more code. I'm sure we can help you figure it out.

Shing Yip