xref: /aosp_15_r20/external/compiler-rt/test/cfi/cross-dso/icall/diag.cpp (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
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