4

I'm reversing a program which I assume was compiled with MSVC. It's seeming like the first entry in each vtable is the class' destructor. However, when I look at the disassembly and decompilation, it seems like the destructors all take a second argument, and that the object's memory is only freed if that second argument is nonnull.

What is the purpose for this second argument? I would think that, if it's a destructor, the class should always be destructed and its memory freed. So why the second argument which could prohibit the memory from being freed up?

3
  • In C++ there is a construct called "placement new operator". It can be used to construct object in pre-allocated area. For example on the stack. In such case when memory was not allocated for the object, destructor cannot released that memory. Please take a look at "How to delete the memory allocated by placement new ?" on geeksforgeeks.org/placement-new-operator-cpp there is nice example. It's possible to call destructor directly like this : " // No delete : Explicit call to Destructor. pe->~Complex(); "
    – malikcjm
    Apr 16 '20 at 5:57
  • Interesting, I didn't know about placement new. So, then, a call to delete object in the original code might call the destructor with a non-null second argument, while a call to the destructor, say, because the object was on the stack and went out of scope would have a null second argument, and thus not try to deallocate memory which was on the stack. Am I understanding correctly?
    – sasschary
    Apr 16 '20 at 6:17
  • This is exactly how I understood usage of that second parameter.
    – malikcjm
    Apr 16 '20 at 19:52
3

These wrappers are used in classes with virtual destructors to cover two situations:

  1. ensure that the correct operator delete is called after the object's destruction via delete pClass; statement

  2. deletion of arrays allocated via new Class[N] expression in the delete [] class_array; statement to ensure the correct number of items gets deleted using the correct operator delete and handle potential exceptions during the process

From my old article:

When class has a virtual destructor, compiler generates a helper function - deleting destructor. Its purpose is to make sure that a proper operator delete gets called when destructing a class. Pseudo-code for a deleting destructor looks like following:

virtual void * A::'scalar deleting destructor'(uint flags)
{
  this->~A();
  if (flags&1) A::operator delete(this);
};

The address of this function is placed into the vftable instead of the destructor's address. This way, if another class overrides the virtual destructor, operator delete of that class will be called. Though in real code operator delete gets overriden quite rarely, so usually you see a call to the default delete().

Sometimes compiler can also generate a vector deleting destructor. Its code looks like this:

virtual void * A::'vector deleting destructor'(uint flags)
{
  if (flags&2) //destructing a vector
  {
    array = ((int*)this)-1; //array size is stored just before the this pointer
    count = array[0];
    'eh vector destructor iterator'(this,sizeof(A),count,A::~A);
    if (flags&1) A::operator delete(array);
  }
  else {
    this->~A();
    if (flags&1) A::operator delete(this);
  }
};

For more details see also C++: Under the Hood by Jan Gray, one of the main developers of Visual C++.

I also recommend you to make some classes with custom operators new/delete and check the generated code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.