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
f()28 void A::f() {}
29
foo()30 void foo() {
31 fprintf(stderr, "foo\n");
32 }
33
34 void *fake_vtable[] = { (void *)&foo };
35
main()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