1

I'm reversing the following smart pointee-like MSVC class Buffer : public Referencable with IDA / Hexrays:

struct Referencable
{
    int m_refs;
};
struct Buffer : Referencable
{
    void* m_pData;
};

This class apparently has no vftable, which I deduce from its (base) constructor not storing any vftable-like structure:

Buffer *__thiscall Buffer::ctor(Buffer *this)
{
    Referencable::ctor(this);
    this->m_pData = NULL;
    return this;
}
Referencable *__thiscall Referencable::ctor(Referencable *this)
{
    // <-- no vftable assignment here or anywhere -->
    this->m_refs = 0;
    return this;
}

When this object is being deleted, I see the following method:

Buffer *__thiscall Buffer::ddtor(Buffer *this, char flags)
{
    Buffer::dtor(this);
    if ( (flags & 1) != 0 )
        operator delete(this);
    return this;
}
void __thiscall Buffer::dtor(Buffer *this)
{
    free(this->m_pData);
    Referencable::dtor(this);
}
void __thiscall Referencable::dtor(Referencable *this)
{
    ; // nop
}

(I can assure that this is indeed the deletion method belonging to this class due to how the capturing smart pointer calls it)

According to igorsk's Reversing Microsoft Visual C++ Part II: Classes, Methods and RTTI article, Buffer::ddtor seems to be a deletion destructor, which however are only available to classes with virtual destructors:

  1. Deleting Destructors

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);
};

Thus my class seems to contradict another statement in that article, mentioning a virtual deletion destructor call which does not exist in my assembly (the deletion destructor above is called directly by the smart pointer logic):

If A's destructor is virtual, it's invoked virtually:

mov ecx, pA
push 3
mov eax, [ecx] ;fetch vtable pointer      // <-- what vftable? I have none!
call [eax]     ;call deleting destructor

Now I am a little confused.

  • Does this class have a virtual destructor now or not?
  • Is it possible for a deletion destructor to be generated even if I do not have a virtual destructor, and what are the requirements?
  • Or is this what is always generated when I call delete on anything and I simply misunderstood the article?
  • If it helps clearing my confusion, what is the exact difference between a deletion destructor and virtual destructor anyway?

On a postscriptum note I know this assembly quite well otherwise and never noticed any kind of code optimizations (lucky me); I wonder how a vftable could've been optimized out anyway.

1 Answer 1

1

Apparently I was confused over the articles wording due to initially seeing deletion destructors as virtual destructors. I analyzed a small scratchpad program and realized the following:

  • Deletion destructors (in PDBs referred to as "scalar deleting destructor") are generated whenever I call delete on an object with a destructor, no matter if it is virtual or not. It's practically there to ensure to call the user destructor code and then actually free the memory.
  • Only as soon as I make the destructor virtual (or declare another method virtual), MSVC always generates a vftable (what else?).

There are probably exceptions to these observations but so far I haven't seen them. Feel free to expand my knowledge here!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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