1*7c3d14c8STreehugger Robot // Cross-DSO diagnostics.
2*7c3d14c8STreehugger Robot // The rules are:
3*7c3d14c8STreehugger Robot // * If the library needs diagnostics, the main executable must request at
4*7c3d14c8STreehugger Robot // least some diagnostics as well (to link the diagnostic runtime).
5*7c3d14c8STreehugger Robot // * -fsanitize-trap on the caller side overrides everything.
6*7c3d14c8STreehugger Robot // * otherwise, the callee decides between trap/recover/norecover.
7*7c3d14c8STreehugger Robot
8*7c3d14c8STreehugger Robot // Full-recover.
9*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so
10*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso_diag -g %s -o %t %t-so.so
11*7c3d14c8STreehugger Robot
12*7c3d14c8STreehugger Robot // RUN: %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-DIAG --check-prefix=CAST-DIAG \
13*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-DIAG --check-prefix=ALL-RECOVER
14*7c3d14c8STreehugger Robot
15*7c3d14c8STreehugger Robot // RUN: %t i_v 2>&1 | FileCheck %s --check-prefix=ICALL-DIAG --check-prefix=CAST-NODIAG \
16*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-DIAG --check-prefix=ALL-RECOVER
17*7c3d14c8STreehugger Robot
18*7c3d14c8STreehugger Robot // RUN: %t _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-DIAG \
19*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-DIAG --check-prefix=ALL-RECOVER
20*7c3d14c8STreehugger Robot
21*7c3d14c8STreehugger Robot // RUN: %t ic_ 2>&1 | FileCheck %s --check-prefix=ICALL-DIAG --check-prefix=CAST-DIAG \
22*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-NODIAG --check-prefix=ALL-RECOVER
23*7c3d14c8STreehugger Robot
24*7c3d14c8STreehugger Robot // Trap on icall, no-recover on cast.
25*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \
26*7c3d14c8STreehugger Robot // RUN: -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so
27*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \
28*7c3d14c8STreehugger Robot // RUN: -g %s -o %t %t-so.so
29*7c3d14c8STreehugger Robot
30*7c3d14c8STreehugger Robot // RUN: %expect_crash %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
31*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL
32*7c3d14c8STreehugger Robot
33*7c3d14c8STreehugger Robot // RUN: not %t _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-DIAG \
34*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-NODIAG --check-prefix=CAST-FATAL
35*7c3d14c8STreehugger Robot
36*7c3d14c8STreehugger Robot // RUN: %t __v 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
37*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-DIAG
38*7c3d14c8STreehugger Robot
39*7c3d14c8STreehugger Robot // Callee: trap on icall, no-recover on cast.
40*7c3d14c8STreehugger Robot // Caller: recover on everything.
41*7c3d14c8STreehugger Robot // The same as in the previous case, behaviour is decided by the callee.
42*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \
43*7c3d14c8STreehugger Robot // RUN: -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so
44*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso_diag \
45*7c3d14c8STreehugger Robot // RUN: -g %s -o %t %t-so.so
46*7c3d14c8STreehugger Robot
47*7c3d14c8STreehugger Robot // RUN: %expect_crash %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
48*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL
49*7c3d14c8STreehugger Robot
50*7c3d14c8STreehugger Robot // RUN: not %t _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-DIAG \
51*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-NODIAG --check-prefix=CAST-FATAL
52*7c3d14c8STreehugger Robot
53*7c3d14c8STreehugger Robot // RUN: %t __v 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
54*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-DIAG
55*7c3d14c8STreehugger Robot
56*7c3d14c8STreehugger Robot // Caller in trapping mode, callee with full diagnostic+recover.
57*7c3d14c8STreehugger Robot // Caller wins.
58*7c3d14c8STreehugger Robot // cfi-nvcall is non-trapping in the main executable to link the diagnostic runtime library.
59*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso_diag \
60*7c3d14c8STreehugger Robot // RUN: -g -DSHARED_LIB %s -fPIC -shared -o %t-so.so
61*7c3d14c8STreehugger Robot // RUN: %clangxx_cfi_dso -fno-sanitize-trap=cfi-nvcall \
62*7c3d14c8STreehugger Robot // RUN: -g %s -o %t %t-so.so
63*7c3d14c8STreehugger Robot
64*7c3d14c8STreehugger Robot // RUN: %expect_crash %t icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
65*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL
66*7c3d14c8STreehugger Robot
67*7c3d14c8STreehugger Robot // RUN: %expect_crash %t _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
68*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-NODIAG --check-prefix=CAST-FATAL
69*7c3d14c8STreehugger Robot
70*7c3d14c8STreehugger Robot // RUN: %expect_crash %t __v 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \
71*7c3d14c8STreehugger Robot // RUN: --check-prefix=VCALL-NODIAG --check-prefix=VCALL-FATAL
72*7c3d14c8STreehugger Robot
73*7c3d14c8STreehugger Robot // REQUIRES: cxxabi
74*7c3d14c8STreehugger Robot
75*7c3d14c8STreehugger Robot #include <assert.h>
76*7c3d14c8STreehugger Robot #include <stdio.h>
77*7c3d14c8STreehugger Robot #include <string.h>
78*7c3d14c8STreehugger Robot
79*7c3d14c8STreehugger Robot struct A {
80*7c3d14c8STreehugger Robot virtual void f();
81*7c3d14c8STreehugger Robot };
82*7c3d14c8STreehugger Robot
83*7c3d14c8STreehugger Robot void *create_B();
84*7c3d14c8STreehugger Robot
85*7c3d14c8STreehugger Robot #ifdef SHARED_LIB
86*7c3d14c8STreehugger Robot
87*7c3d14c8STreehugger Robot #include "../../utils.h"
88*7c3d14c8STreehugger Robot struct B {
89*7c3d14c8STreehugger Robot virtual void f();
90*7c3d14c8STreehugger Robot };
f()91*7c3d14c8STreehugger Robot void B::f() {}
92*7c3d14c8STreehugger Robot
create_B()93*7c3d14c8STreehugger Robot void *create_B() {
94*7c3d14c8STreehugger Robot create_derivers<B>();
95*7c3d14c8STreehugger Robot return (void *)(new B());
96*7c3d14c8STreehugger Robot }
97*7c3d14c8STreehugger Robot
98*7c3d14c8STreehugger Robot #else
99*7c3d14c8STreehugger Robot
f()100*7c3d14c8STreehugger Robot void A::f() {}
101*7c3d14c8STreehugger Robot
main(int argc,char * argv[])102*7c3d14c8STreehugger Robot int main(int argc, char *argv[]) {
103*7c3d14c8STreehugger Robot assert(argc == 2);
104*7c3d14c8STreehugger Robot assert(strlen(argv[1]) == 3);
105*7c3d14c8STreehugger Robot
106*7c3d14c8STreehugger Robot // ICALL-FATAL: =0=
107*7c3d14c8STreehugger Robot // CAST-FATAL: =0=
108*7c3d14c8STreehugger Robot // VCALL-FATAL: =0=
109*7c3d14c8STreehugger Robot // ALL-RECOVER: =0=
110*7c3d14c8STreehugger Robot fprintf(stderr, "=0=\n");
111*7c3d14c8STreehugger Robot
112*7c3d14c8STreehugger Robot void *p;
113*7c3d14c8STreehugger Robot if (argv[1][0] == 'i') {
114*7c3d14c8STreehugger Robot // ICALL-DIAG: runtime error: control flow integrity check for type 'void *(int)' failed during indirect function call
115*7c3d14c8STreehugger Robot // ICALL-DIAG-NEXT: note: create_B() defined here
116*7c3d14c8STreehugger Robot // ICALL-NODIAG-NOT: runtime error: control flow integrity check {{.*}} during indirect function call
117*7c3d14c8STreehugger Robot p = ((void *(*)(int))create_B)(42);
118*7c3d14c8STreehugger Robot } else {
119*7c3d14c8STreehugger Robot p = create_B();
120*7c3d14c8STreehugger Robot }
121*7c3d14c8STreehugger Robot
122*7c3d14c8STreehugger Robot // ICALL-FATAL-NOT: =1=
123*7c3d14c8STreehugger Robot // CAST-FATAL: =1=
124*7c3d14c8STreehugger Robot // VCALL-FATAL: =1=
125*7c3d14c8STreehugger Robot // ALL-RECOVER: =1=
126*7c3d14c8STreehugger Robot fprintf(stderr, "=1=\n");
127*7c3d14c8STreehugger Robot
128*7c3d14c8STreehugger Robot A *a;
129*7c3d14c8STreehugger Robot if (argv[1][1] == 'c') {
130*7c3d14c8STreehugger Robot // CAST-DIAG: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type
131*7c3d14c8STreehugger Robot // CAST-DIAG-NEXT: note: vtable is of type '{{(struct )?}}B'
132*7c3d14c8STreehugger Robot // CAST-NODIAG-NOT: runtime error: control flow integrity check {{.*}} during cast to unrelated type
133*7c3d14c8STreehugger Robot a = (A*)p;
134*7c3d14c8STreehugger Robot } else {
135*7c3d14c8STreehugger Robot // Invisible to CFI.
136*7c3d14c8STreehugger Robot memcpy(&a, &p, sizeof(a));
137*7c3d14c8STreehugger Robot }
138*7c3d14c8STreehugger Robot
139*7c3d14c8STreehugger Robot // ICALL-FATAL-NOT: =2=
140*7c3d14c8STreehugger Robot // CAST-FATAL-NOT: =2=
141*7c3d14c8STreehugger Robot // VCALL-FATAL: =2=
142*7c3d14c8STreehugger Robot // ALL-RECOVER: =2=
143*7c3d14c8STreehugger Robot fprintf(stderr, "=2=\n");
144*7c3d14c8STreehugger Robot
145*7c3d14c8STreehugger Robot // VCALL-DIAG: runtime error: control flow integrity check for type 'A' failed during virtual call
146*7c3d14c8STreehugger Robot // VCALL-DIAG-NEXT: note: vtable is of type '{{(struct )?}}B'
147*7c3d14c8STreehugger Robot // VCALL-NODIAG-NOT: runtime error: control flow integrity check {{.*}} during virtual call
148*7c3d14c8STreehugger Robot if (argv[1][2] == 'v') {
149*7c3d14c8STreehugger Robot a->f(); // UB here
150*7c3d14c8STreehugger Robot }
151*7c3d14c8STreehugger Robot
152*7c3d14c8STreehugger Robot // ICALL-FATAL-NOT: =3=
153*7c3d14c8STreehugger Robot // CAST-FATAL-NOT: =3=
154*7c3d14c8STreehugger Robot // VCALL-FATAL-NOT: =3=
155*7c3d14c8STreehugger Robot // ALL-RECOVER: =3=
156*7c3d14c8STreehugger Robot fprintf(stderr, "=3=\n");
157*7c3d14c8STreehugger Robot
158*7c3d14c8STreehugger Robot }
159*7c3d14c8STreehugger Robot #endif
160