0

When I use virtual destructor of struct M, operator new after delete operator return point to other address.

struct M {
    virtual ~M() = default;
};

struct D : public M {
    int* b = nullptr;
};

struct C : public M {
    int* c = nullptr, *b = nullptr;  
    long d = 10;
};

int main() {

    M* f;
    M* d;

    f = new D;
    static_cast<D*>(f)->b = new int(10);
    std::cout << f << ":" << sizeof(*f) << std::endl; // 0x23c1c20 : 8
    delete f;

    d = new C;
    std::cout << d << ":" << sizeof(*d) << std::endl; // 0x23c2c70 : 8
    delete d;

    return 0;
}

But if destructor of struct M is non-virtual operator new return same address.

struct M {
    ~M() = default;
};

...

int main() {

    M* f;
    M* d;

    f = new D;
    static_cast<D*>(f)->b = new int(10);
    std::cout << f << ":" << sizeof(*f) << std::endl; // 0x23c1c20 : 1
    delete f;

    d = new C;
    std::cout << d << ":" << sizeof(*d) << std::endl; // 0x23c1c20 : 1
    delete d;

    return 0;
}

And the size of the objects is different.

Why is this happening?

2
  • 6
    It is undefined behavior to not have a virtual destructor when deleting from a base pointer. Any behavior you observe is a consequence of that and not really worth digging into. Commented Apr 17, 2019 at 13:31
  • 2
    Because the standard specifies that the first case has well-defined behaviour, and the second case has undefined behaviour. Commented Apr 17, 2019 at 13:32

1 Answer 1

1

I will start from the second question.

"Why the size of the object is different?" - the virtual is a key here.

Every class/struct that have a virtual function contain a pointer to virtual table. In this case the size of M will be equal size of pointer on your machine. I guess that you have 64-bit machine, and the size of pointer is equal 8 bytes. In the example where 'virtual' keyword was removed the size of empty class is 1 byte.

More about virtual function and tables you can read here: https://pabloariasal.github.io/2017/06/10/understanding-virtual-tables/

About your first question about reusing address memory on heap I highly recommend you to read first part of https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/

In a brief, the allocation of memory is done by chunk. In the first example (with virtual destructor) both classes are extended by pointer to virtual table. New allocated memory doesn't fit into dealocated chunk of memory, so the new address is found. In the second one the new allocated memory fit into freed space and is reused.

You can try to recompile you example with virtual function but with removed long d from struct C. It may turn out that the address will be the same now.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.