1 // RUN: %clangxx_cfi -o %t %s 2 // RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s 3 4 // RUN: %clangxx_cfi -DB32 -o %t %s 5 // RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s 6 7 // RUN: %clangxx_cfi -DB64 -o %t %s 8 // RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s 9 10 // RUN: %clangxx_cfi -DBM -o %t %s 11 // RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s 12 13 // RUN: %clangxx -o %t %s 14 // RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s 15 16 // Tests that the CFI mechanism crashes the program when a virtual table is 17 // replaced with a compatible table of function pointers that does not belong to 18 // any class, by manually overwriting the virtual table of an object and 19 // attempting to make a call through it. 20 21 #include <stdio.h> 22 #include "utils.h" 23 24 struct A { 25 virtual void f(); 26 }; 27 28 void A::f() {} 29 30 void foo() { 31 fprintf(stderr, "foo\n"); 32 } 33 34 void *fake_vtable[] = { (void *)&foo }; 35 36 int main() { 37 #ifdef B32 38 break_optimization(new Deriver<A, 0>); 39 #endif 40 41 #ifdef B64 42 break_optimization(new Deriver<A, 0>); 43 break_optimization(new Deriver<A, 1>); 44 #endif 45 46 #ifdef BM 47 break_optimization(new Deriver<A, 0>); 48 break_optimization(new Deriver<A, 1>); 49 break_optimization(new Deriver<A, 2>); 50 #endif 51 52 A *a = new A; 53 *((void **)a) = fake_vtable; // UB here 54 break_optimization(a); 55 56 // CFI: 1 57 // NCFI: 1 58 fprintf(stderr, "1\n"); 59 60 // CFI-NOT: foo 61 // NCFI: foo 62 a->f(); 63 64 // CFI-NOT: 2 65 // NCFI: 2 66 fprintf(stderr, "2\n"); 67 } 68