Implicit null check in object instantiation

When an object with a vtable is instantiated, the vtable is constructed in the allocated buffer. So, what happens if the buffer allocation fails?

In the case buffer allocation is done by default allocator, std::bad_alloc() is raised before vtable construction – no problem. However, there are cases where new operator is hooked to return 0 on failure for whatever reasons. (eg. compatibility with older compilers).

It would be nightmare if null pointer access violation happened in vtable construction. Therefore, Visual C++ compiler has to check the result of buffer allocation. The check happens even when you use standard new operator with std::bad_alloc exception, because the actual allocation might be hooked through set_new_handler.

// source code
int main(){
    Super* p = new Sub;
    p->func();
    return 0;
}

// peudo compiler generated code
int main(){
    char* buffer = new sizeof(Sub);
    if(buffer){
      construct_vtable(buffer);
    }
    p->func();
    return 0;
}

If you checks p before calling func(), compiler optimizer combines these two checks.

// source code
int main(){
    Super* p = new Sub;
    if(p){
      p->func();
    }
    return 0;
}

// peudo compiler generated code
int main(){
    char* buffer = new sizeof(Sub);
    if(buffer){
      construct_vtable(buffer);
      p->func();
    }
    return 0;
}

But, this optimization may not work if there is nother statement in between.

// source code
int main(){
    Super* p = new Sub;
    printf("foo");
    if(p){
      p->func();
    }
    return 0;
}

// peudo compiler generated code
int main(){
    char* buffer = new sizeof(Sub);
    if(buffer){
      construct_vtable(buffer);
    }
    prinf("foo");
    if(p){
      p->func();
    }
    return 0;
}

Sample code and actual machine code is here.

class Super {
public:
    virtual void func() = 0;
};

class Sub : public Super {
public:
    virtual void func() {
    }
};

int main(){
    Super* p = new Sub;
    p->func();
    return 0;
}

00401010 6a04            push    4
00401012 e86f000000      call    se!operator new (00401086)
00401017 83c404          add     esp,4
0040101a 85c0            test    eax,eax
0040101c 7411            je      se!main+0x1f (0040102f)

se!main+0xe:
0040101e c70000214000    mov     dword ptr [eax],offset se!Sub::`vftable’ (00402100)
00401024 8b10            mov     edx,dword ptr [eax]
00401026 8bc8            mov     ecx,eax
00401028 8b02            mov     eax,dword ptr [edx]
0040102a ffd0            call    eax
0040102c 33c0            xor     eax,eax
0040102e c3              ret

se!main+0x1f:
0040102f 33c0            xor     eax,eax
00401031 8b10            mov     edx,dword ptr [eax]
00401033 8bc8            mov     ecx,eax
00401035 8b02            mov     eax,dword ptr [edx]
00401037 ffd0            call    eax
00401039 33c0            xor     eax,eax
0040103b c3              ret

Advertisements

About Moto

Engineer who likes coding
This entry was posted in C++. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s