161 lines · cpp
1// Cross-DSO diagnostics.2// The rules are:3// * If the library needs diagnostics, the main executable must request at4// least some diagnostics as well (to link the diagnostic runtime).5// * -fsanitize-trap on the caller side overrides everything.6// * otherwise, the callee decides between trap/recover/norecover.7 8// Full-recover.9// RUN: mkdir -p %t.dir && cd %t.dir10// RUN: %clangxx_cfi_dso_diag -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so11// RUN: %clangxx_cfi_dso_diag -g %s -o %t.dir/exe %ld_flags_rpath_exe12 13// RUN: %t.dir/exe icv 2>&1 | FileCheck %s --check-prefix=ICALL-DIAG --check-prefix=CAST-DIAG \14// RUN: --check-prefix=VCALL-DIAG --check-prefix=ALL-RECOVER15 16// RUN: %t.dir/exe i_v 2>&1 | FileCheck %s --check-prefix=ICALL-DIAG --check-prefix=CAST-NODIAG \17// RUN: --check-prefix=VCALL-DIAG --check-prefix=ALL-RECOVER18 19// RUN: %t.dir/exe _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-DIAG \20// RUN: --check-prefix=VCALL-DIAG --check-prefix=ALL-RECOVER21 22// RUN: %t.dir/exe ic_ 2>&1 | FileCheck %s --check-prefix=ICALL-DIAG --check-prefix=CAST-DIAG \23// RUN: --check-prefix=VCALL-NODIAG --check-prefix=ALL-RECOVER24 25// Trap on icall, no-recover on cast.26// RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \27// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so28// RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \29// RUN: -g %s -o %t.dir/exe %ld_flags_rpath_exe30 31// RUN: %expect_crash %t.dir/exe icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \32// RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL33 34// RUN: not %t.dir/exe _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-DIAG \35// RUN: --check-prefix=VCALL-NODIAG --check-prefix=CAST-FATAL36 37// RUN: %t.dir/exe __v 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \38// RUN: --check-prefix=VCALL-DIAG39 40// Callee: trap on icall, no-recover on cast.41// Caller: recover on everything.42// The same as in the previous case, behaviour is decided by the callee.43// RUN: %clangxx_cfi_dso_diag -fsanitize-trap=cfi-icall -fno-sanitize-recover=cfi-unrelated-cast \44// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so45// RUN: %clangxx_cfi_dso_diag \46// RUN: -g %s -o %t.dir/exe %ld_flags_rpath_exe47 48// RUN: %expect_crash %t.dir/exe icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \49// RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL50 51// RUN: not %t.dir/exe _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-DIAG \52// RUN: --check-prefix=VCALL-NODIAG --check-prefix=CAST-FATAL53 54// RUN: %t.dir/exe __v 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \55// RUN: --check-prefix=VCALL-DIAG56 57// Caller in trapping mode, callee with full diagnostic+recover.58// Caller wins.59// cfi-nvcall is non-trapping in the main executable to link the diagnostic runtime library.60// RUN: %clangxx_cfi_dso_diag \61// RUN: -g -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so62// RUN: %clangxx_cfi_dso -fno-sanitize-trap=cfi-nvcall \63// RUN: -g %s -o %t.dir/exe %ld_flags_rpath_exe64 65// RUN: %expect_crash %t.dir/exe icv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \66// RUN: --check-prefix=VCALL-NODIAG --check-prefix=ICALL-FATAL67 68// RUN: %expect_crash %t.dir/exe _cv 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \69// RUN: --check-prefix=VCALL-NODIAG --check-prefix=CAST-FATAL70 71// RUN: %expect_crash %t.dir/exe __v 2>&1 | FileCheck %s --check-prefix=ICALL-NODIAG --check-prefix=CAST-NODIAG \72// RUN: --check-prefix=VCALL-NODIAG --check-prefix=VCALL-FATAL73 74// REQUIRES: cxxabi75 76#include <assert.h>77#include <stdio.h>78#include <string.h>79 80struct A {81 virtual void f();82};83 84void *create_B();85 86#ifdef SHARED_LIB87 88#include "../../utils.h"89struct B {90 virtual void f();91};92void B::f() {}93 94void *create_B() {95 create_derivers<B>();96 return (void *)(new B());97}98 99#else100 101void A::f() {}102 103int main(int argc, char *argv[]) {104 assert(argc == 2);105 assert(strlen(argv[1]) == 3);106 107 // ICALL-FATAL: =0=108 // CAST-FATAL: =0=109 // VCALL-FATAL: =0=110 // ALL-RECOVER: =0=111 fprintf(stderr, "=0=\n");112 113 void *p;114 if (argv[1][0] == 'i') {115 // ICALL-DIAG: runtime error: control flow integrity check for type 'void *(int)' failed during indirect function call116 // ICALL-DIAG-NEXT: note: create_B() defined here117 // ICALL-NODIAG-NOT: runtime error: control flow integrity check {{.*}} during indirect function call118 p = ((void *(*)(int))create_B)(42);119 } else {120 p = create_B();121 }122 123 // ICALL-FATAL-NOT: =1=124 // CAST-FATAL: =1=125 // VCALL-FATAL: =1=126 // ALL-RECOVER: =1=127 fprintf(stderr, "=1=\n");128 129 A *a;130 if (argv[1][1] == 'c') {131 // CAST-DIAG: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type132 // CAST-DIAG-NEXT: note: vtable is of type '{{(struct )?}}B'133 // CAST-NODIAG-NOT: runtime error: control flow integrity check {{.*}} during cast to unrelated type134 a = (A*)p;135 } else {136 // Invisible to CFI.137 memcpy(&a, &p, sizeof(a));138 }139 140 // ICALL-FATAL-NOT: =2=141 // CAST-FATAL-NOT: =2=142 // VCALL-FATAL: =2=143 // ALL-RECOVER: =2=144 fprintf(stderr, "=2=\n");145 146 // VCALL-DIAG: runtime error: control flow integrity check for type 'A' failed during virtual call147 // VCALL-DIAG-NEXT: note: vtable is of type '{{(struct )?}}B'148 // VCALL-NODIAG-NOT: runtime error: control flow integrity check {{.*}} during virtual call149 if (argv[1][2] == 'v') {150 a->f(); // UB here151 }152 153 // ICALL-FATAL-NOT: =3=154 // CAST-FATAL-NOT: =3=155 // VCALL-FATAL-NOT: =3=156 // ALL-RECOVER: =3=157 fprintf(stderr, "=3=\n");158 159}160#endif161