Search code examples
c++unreal-engine4

Checking virtual function table using *(void**)this


The unreal engine source code has this bit in a validity check function:

if (*(void**)this == nullptr)
{
    UE_LOG(LogUObjectBase, Error, TEXT("Virtual functions table is invalid."));
    return false;
}

In this case this being a pointer to an instanced object of a class. I understand what the conversion and dereferencing does on a surface level but I am not quite clear how this helps check if the vtable is valid.


Solution

  • There are two separate questions here: what does this code do, and does it work?

    One common way that vtables are implemented is by storing a pointer to the vtable at the base of the object. So, for example, on a 32-bit machine, the first four bytes of the object would be a pointer to the vtable, and on a 64-bit machine the first eight bytes of the object would be a pointer to the vtable.

    With that in mind, let’s think about what *(void**)this does. The this pointer points to the base of the object. We want to interpret the beginning of that object as a pointer to a vtable, so we want to get the value of the pointer at the base of the object. However, we don’t have a name for that pointer, so we can’t look it up by name, and because the vtable is set up by the compiler there is no C++ type that corresponds to “a vtable.” So instead, we’ll do the following. We’ll envision the pointer we want to read as being a void* (a pointer to “something whose type we don’t know.”) The this pointer is pointing right at that void*, so we’ll introduce a cast of (void**)this to say “pretend that this points at a void*.” We then dereference that pointer to read the void* that’s stored there, which is our vtable pointer. Collectively, that gives us *(void**)this.

    The next question is why the null-check works. In a general, this safety check won’t work. It presumes that when space for an object is allocated, the memory is set to all 0s before the object is constructed. Assuming that’s the case, if the vtable pointer hasn’t been set up, then the bytes allocated to it would be 0s, which on some C++ implementations is treated as a null pointer. So the check you’ve listed here would then read the vtable pointer, see if it’s null, and then report an error if it is.

    However, there’s a lot of assumptions there - that the memory is nulled out before the object is constructed, that the vtable is at the exact base of the object, etc. I’m not familiar with the specifics of the Unreal engine, but I assume it probably is set up to ensure these requirements are met.