12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- #include <dlfcn.h>
- #include <assert.h>
- #include <unistd.h>
- #include <vtv_fail.h>
- extern "C" int printf(const char *, ...);
- extern "C" int sprintf(char *, const char*, ...);
- static int counter = 0;
- extern int failures;
- template <int i> struct base
- {
- virtual char * whoami() {
- static char sl[100];
- sprintf(sl, "I am base %d", i);
- return sl;
- }
- virtual void inc() { counter += i; }
- };
- template <int i> struct derived: base<i>
- {
- virtual char * whoami() {
- static char sl[100];
- sprintf(sl, "I am derived %d", i);
- return sl;
- }
- virtual void inc() { counter += (10*i); }
- };
- // We don't use this class. It is just here so that the
- // compiler does not devirtualize calls to derived::inc()
- template <int i> struct derived2: derived<i>
- {
- virtual void inc() { counter += (20*i); }
- };
- static base<TPID> * bp = new base<TPID>();
- static derived<TPID> * dp = new derived<TPID>();
- static base<TPID> * dbp = new derived<TPID>();
- // Given 2 pointers to C++ objects (non PODs), exchange the pointers to vtable
- static void exchange_vtptr(void * object1_ptr, void * object2_ptr)
- {
- void ** object1_vtptr_ptr = (void **)object1_ptr;
- void ** object2_vtptr_ptr = (void **)object2_ptr;
- void * object1_vtptr = *object1_vtptr_ptr;
- void * object2_vtptr = *object2_vtptr_ptr;
- *object1_vtptr_ptr = object2_vtptr;
- *object2_vtptr_ptr = object1_vtptr;
- }
- #define BUILD_NAME(NAME,ID) NAME##ID
- #define EXPAND(NAME,X) BUILD_NAME(NAME,X)
- extern "C" void EXPAND(so_entry_,TPID)(void)
- {
- int prev_counter;
- int prev_failures;
- counter = 0;
- bp->inc();
- dp->inc();
- dbp->inc();
- assert(counter == (TPID + 10*TPID + 10*TPID));
- prev_counter = counter;
- exchange_vtptr(bp, dp);
- bp->inc(); // This one should succeed but it is calling the wrong member
- if (counter != (prev_counter + 10*TPID))
- {
- printf("TPID=%d whoami=%s wrong counter value prev_counter=%d counter=%d\n", TPID, bp->whoami(), prev_counter, counter);
- sleep(2);
- }
- assert(counter == (prev_counter + 10*TPID));
- // printf("Pass first attack!\n");
- // This one should fail verification!. So it should jump to __vtv_verify_fail above.
- prev_failures = failures;
- dp->inc();
- // this code may be executed by multiple threads at the same time. So, just verify the number of failures has
- // increased as opposed to check for increase by 1.
- assert(failures > prev_failures);
- assert(counter == (prev_counter + 10*TPID + TPID));
- // printf("TPDI=%d counter %d\n", TPID, counter);
- // printf("Pass second attack!\n");
- // restore the vtable pointers to the original state.
- // This is very important. For some reason the dlclose is not "really" closing the library so when we reopen it we are
- // getting the old memory state.
- exchange_vtptr(bp, dp);
- }
|