Posted by: rmn on: 14/08/2009
Most compilers implement dynamic binding by using a vtable whose pointer resides at the beginning of each object’s memory footprint (something along the lines of [vtable-pointer|..members..], if we are not considering virtual inheritance).
Keeping this idea in mind, why don’t we go ahead and attempt to change that vtable pointer?
#include <iostream>
using std::cout;
struct A {
virtual void f () { cout << "a:" << n; }
A () : n(1) {}
int n;
};
struct B : A {
void f () { cout << "b:" << n; }
B () { n = 2; }
};
int main () {
A *a = new A();
A *b = new B();
// lets change a's vtable to b's
*reinterpret_cast<int**>(a) = *reinterpret_cast<int**>(b);
a->f(); // huray, B::f() is invoked!
}
Notice we surely did not touch the object itself, since the member did not change.
Another thing worth saying is that this trick is unlikely to work when using 64bit pointers since we’re using an (arbitrary) int* type, but that could easily be solved using a compile time #defined typedef.
One extra thing i would like to mention is that i have tried to change specific entries inside the vtable, but the compiler marks that memory area as read-only and therefore throws an exception whenever modification attempts are made. Here is the attempted piece of code:
#include <iostream>
using std::cout;
struct A {
virtual void f () { cout << "f"; }
virtual void g () { cout << "g"; }
};
int main () {
A *a = new A();
int **vtable = *reinterpret_cast<int***>(a);
vtable[0] = vtable[1];
a->f();
}
This change to the vtable would make the call to f() actually invoke g().
Recent comments