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?
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.