diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-09-06 18:41:23 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-09-06 18:41:23 +0000 |
commit | f31bcc68c72371a2bf63aead9f3373a1ff2053b6 (patch) | |
tree | b259e5d585da0f8cde9579939a74d5ef44c72abd /test/cfi | |
parent | cd2dd3df15523e2be8d2bbace27641d6ac9fa40d (diff) | |
download | src-f31bcc68c72371a2bf63aead9f3373a1ff2053b6.tar.gz src-f31bcc68c72371a2bf63aead9f3373a1ff2053b6.zip |
Import compiler-rt 3.7.0 release (r246257).vendor/compiler-rt/compiler-rt-release_370-r246257
Notes
Notes:
svn path=/vendor/compiler-rt/dist/; revision=287516
svn path=/vendor/compiler-rt/compiler-rt-release_370-r246257/; revision=287517; tag=vendor/compiler-rt/compiler-rt-release_370-r246257
Diffstat (limited to 'test/cfi')
-rw-r--r-- | test/cfi/CMakeLists.txt | 17 | ||||
-rw-r--r-- | test/cfi/README.txt | 8 | ||||
-rw-r--r-- | test/cfi/anon-namespace.cpp | 35 | ||||
-rw-r--r-- | test/cfi/bad-cast.cpp | 150 | ||||
-rw-r--r-- | test/cfi/lit.cfg | 30 | ||||
-rw-r--r-- | test/cfi/multiple-inheritance.cpp | 44 | ||||
-rw-r--r-- | test/cfi/nvcall.cpp | 72 | ||||
-rw-r--r-- | test/cfi/overwrite.cpp | 35 | ||||
-rw-r--r-- | test/cfi/sibling.cpp | 67 | ||||
-rw-r--r-- | test/cfi/simple-fail.cpp | 81 | ||||
-rw-r--r-- | test/cfi/simple-pass.cpp | 26 | ||||
-rw-r--r-- | test/cfi/vdtor.cpp | 31 |
12 files changed, 481 insertions, 115 deletions
diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index f519fb089505..21463ac408de 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -9,15 +9,32 @@ if(NOT COMPILER_RT_STANDALONE_BUILD) FileCheck clang not + ubsan ) if(LLVM_ENABLE_PIC AND LLVM_BINUTILS_INCDIR) list(APPEND CFI_TEST_DEPS LLVMgold ) endif() + if(APPLE) + list(APPEND CFI_TEST_DEPS + LTO + ) + endif() + if(WIN32 AND EXISTS ${CMAKE_SOURCE_DIR}/tools/lld) + list(APPEND CFI_TEST_DEPS + lld + ) + endif() endif() add_lit_testsuite(check-cfi "Running the cfi regression tests" ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${CFI_TEST_DEPS}) + +add_lit_target(check-cfi-and-supported "Running the cfi regression tests" + ${CMAKE_CURRENT_BINARY_DIR} + PARAMS check_supported=1 + DEPENDS ${CFI_TEST_DEPS}) + set_target_properties(check-cfi PROPERTIES FOLDER "Tests") diff --git a/test/cfi/README.txt b/test/cfi/README.txt new file mode 100644 index 000000000000..6b82f5edc235 --- /dev/null +++ b/test/cfi/README.txt @@ -0,0 +1,8 @@ +The tests in this directory use a common convention for exercising the +functionality associated with bit sets of different sizes. When certain +macros are defined the tests instantiate classes that force the bit sets +to be of certain sizes. + +- B32 forces 32-bit bit sets. +- B64 forces 64-bit bit sets. +- BM forces memory bit sets. diff --git a/test/cfi/anon-namespace.cpp b/test/cfi/anon-namespace.cpp index 0c2c689966f1..f25f3405516e 100644 --- a/test/cfi/anon-namespace.cpp +++ b/test/cfi/anon-namespace.cpp @@ -1,27 +1,32 @@ // RUN: %clangxx_cfi -c -DTU1 -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx_cfi -o %t %t1.o %t2.o -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %t1.o %t2.o +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -c -DTU1 -DB32 -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -DB32 -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx_cfi -o %t %t1.o %t2.o -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t2 %t1.o %t2.o +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -c -DTU1 -DB64 -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -DB64 -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx_cfi -o %t %t1.o %t2.o -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t3 %t1.o %t2.o +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx_cfi -c -DTU1 -DBM -o %t1.o %s // RUN: %clangxx_cfi -c -DTU2 -DBM -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx_cfi -o %t %t1.o %t2.o -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t4 %t1.o %t2.o +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s // RUN: %clangxx -c -DTU1 -o %t1.o %s // RUN: %clangxx -c -DTU2 -o %t2.o %S/../cfi/anon-namespace.cpp -// RUN: %clangxx -o %t %t1.o %t2.o -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t5 %t1.o %t2.o +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s + +// RUN: %clangxx_cfi_diag -c -DTU1 -o %t1.o %s +// RUN: %clangxx_cfi_diag -c -DTU2 -o %t2.o %S/../cfi/anon-namespace.cpp +// RUN: %clangxx_cfi_diag -o %t6 %t1.o %t2.o +// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI mechanism treats classes in the anonymous namespace in // different translation units as having distinct identities. This is done by @@ -33,6 +38,8 @@ // are different. It currently does so because bitset names have global scope // so we have to mangle the file path into the bitset name. +// REQUIRES: cxxabi + #include <stdio.h> #include "utils.h" @@ -83,10 +90,14 @@ int main() { // NCFI: 1 fprintf(stderr, "1\n"); + // CFI-DIAG: runtime error: control flow integrity check for type '(anonymous namespace)::B' failed during base-to-derived cast + // CFI-DIAG-NEXT: note: vtable is of type '{{.*}}anonymous namespace{{.*}}::B' + // CFI-DIAG: runtime error: control flow integrity check for type '(anonymous namespace)::B' failed during virtual call + // CFI-DIAG-NEXT: note: vtable is of type '{{.*}}anonymous namespace{{.*}}::B' ((B *)a)->f(); // UB here - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/cfi/bad-cast.cpp b/test/cfi/bad-cast.cpp new file mode 100644 index 000000000000..9ba6f6dbacec --- /dev/null +++ b/test/cfi/bad-cast.cpp @@ -0,0 +1,150 @@ +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t1 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t1 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t1 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t1 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t1 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %t1 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t1 h 2>&1 | FileCheck --check-prefix=PASS %s + +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t2 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t2 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t2 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t2 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t2 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %t2 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t2 h 2>&1 | FileCheck --check-prefix=PASS %s + +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t3 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t3 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t3 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t3 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t3 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %t3 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t3 h 2>&1 | FileCheck --check-prefix=PASS %s + +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t4 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t4 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t4 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t4 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t4 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %expect_crash %t4 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %t4 h 2>&1 | FileCheck --check-prefix=PASS %s + +// RUN: %clangxx_cfi -fsanitize=cfi-cast-strict -o %t5 %s +// RUN: %expect_crash %t5 a 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 b 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 c 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 d 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 e 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 f 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 g 2>&1 | FileCheck --check-prefix=FAIL %s +// RUN: %expect_crash %t5 h 2>&1 | FileCheck --check-prefix=FAIL %s + +// RUN: %clangxx -o %t6 %s +// RUN: %t6 a 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 b 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 c 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 d 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 e 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 f 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 g 2>&1 | FileCheck --check-prefix=PASS %s +// RUN: %t6 h 2>&1 | FileCheck --check-prefix=PASS %s + +// RUN: %clangxx_cfi_diag -o %t7 %s +// RUN: %t7 a 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s +// RUN: %t7 b 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s +// RUN: %t7 c 2>&1 | FileCheck --check-prefix=CFI-DIAG-D %s +// RUN: %t7 g 2>&1 | FileCheck --check-prefix=CFI-DIAG-U %s + +// Tests that the CFI enforcement detects bad casts. + +// REQUIRES: cxxabi + +#include <stdio.h> +#include "utils.h" + +struct A { + virtual void f(); +}; + +void A::f() {} + +struct B : A { + virtual void f(); +}; + +void B::f() {} + +struct C : A { +}; + +int main(int argc, char **argv) { +#ifdef B32 + break_optimization(new Deriver<B, 0>); +#endif + +#ifdef B64 + break_optimization(new Deriver<B, 0>); + break_optimization(new Deriver<B, 1>); +#endif + +#ifdef BM + break_optimization(new Deriver<B, 0>); + break_optimization(new Deriver<B, 1>); + break_optimization(new Deriver<B, 2>); +#endif + + B *b = new B; + break_optimization(b); + + // FAIL: 1 + // PASS: 1 + fprintf(stderr, "1\n"); + + A a; + + // CFI-DIAG-D: runtime error: control flow integrity check for type 'B' failed during base-to-derived cast + // CFI-DIAG-D-NEXT: note: vtable is of type '{{(struct )?}}A' + + // CFI-DIAG-U: runtime error: control flow integrity check for type 'B' failed during cast to unrelated type + // CFI-DIAG-U-NEXT: note: vtable is of type '{{(struct )?}}A' + + switch (argv[1][0]) { + case 'a': + static_cast<B *>(&a); // UB + break; + case 'b': + static_cast<B &>(a); // UB + break; + case 'c': + static_cast<B &&>(a); // UB + break; + case 'd': + static_cast<C *>(&a); // UB, strict only + break; + case 'e': + static_cast<C &>(a); // UB, strict only + break; + case 'f': + static_cast<C &&>(a); // UB, strict only + break; + case 'g': + static_cast<B *>(static_cast<void *>(&a)); // Non-UB bad cast + break; + case 'h': + static_cast<C *>(static_cast<void *>(&a)); // Non-UB bad cast, strict only + break; + } + + // FAIL-NOT: {{^2$}} + // PASS: {{^2$}} + fprintf(stderr, "2\n"); +} diff --git a/test/cfi/lit.cfg b/test/cfi/lit.cfg index d78820daa055..1fa5a1e25137 100644 --- a/test/cfi/lit.cfg +++ b/test/cfi/lit.cfg @@ -1,35 +1,19 @@ import lit.formats import os -import subprocess -import sys config.name = 'cfi' config.suffixes = ['.cpp'] config.test_source_root = os.path.dirname(__file__) -def is_darwin_lto_supported(): - return os.path.exists(os.path.join(config.llvm_shlib_dir, 'libLTO.dylib')) - -def is_linux_lto_supported(): - if not os.path.exists(os.path.join(config.llvm_shlib_dir, 'LLVMgold.so')): - return False - - ld_cmd = subprocess.Popen([config.gold_executable, '--help'], stdout = subprocess.PIPE) - ld_out = ld_cmd.stdout.read().decode() - ld_cmd.wait() - - if not '-plugin' in ld_out: - return False - - return True - clangxx = ' '.join([config.clang] + config.cxx_mode_flags) config.substitutions.append((r"%clangxx ", clangxx + ' ')) - -if sys.platform == 'darwin' and is_darwin_lto_supported(): - config.substitutions.append((r"%clangxx_cfi ", 'env DYLD_LIBRARY_PATH=' + config.llvm_shlib_dir + ' ' + clangxx + ' -fsanitize=cfi ')) -elif sys.platform.startswith('linux') and is_linux_lto_supported(): - config.substitutions.append((r"%clangxx_cfi ", clangxx + ' -fuse-ld=gold -fsanitize=cfi ')) +if config.lto_supported: + clangxx_cfi = ' '.join(config.lto_launch + [clangxx] + config.lto_flags + ['-flto -fsanitize=cfi ']) + config.substitutions.append((r"%clangxx_cfi ", clangxx_cfi)) + config.substitutions.append((r"%clangxx_cfi_diag ", clangxx_cfi + '-fno-sanitize-trap=cfi -fsanitize-recover=cfi ')) else: config.unsupported = True + +if lit_config.params.get('check_supported', None) and config.unsupported: + raise BaseException("Tests unsupported") diff --git a/test/cfi/multiple-inheritance.cpp b/test/cfi/multiple-inheritance.cpp index 523af6f72f2f..e2a9abebb955 100644 --- a/test/cfi/multiple-inheritance.cpp +++ b/test/cfi/multiple-inheritance.cpp @@ -1,26 +1,32 @@ -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: not --crash %t x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t1 x 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: not --crash %t x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t2 x 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: not --crash %t x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t3 x 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: not --crash %t x 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %expect_crash %t4 x 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s -// RUN: %t x 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t5 %s +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %t5 x 2>&1 | FileCheck --check-prefix=NCFI %s + +// RUN: %clangxx_cfi_diag -o %t6 %s +// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG2 %s +// RUN: %t6 x 2>&1 | FileCheck --check-prefix=CFI-DIAG1 %s // Tests that the CFI mechanism is sensitive to multiple inheritance and only // permits calls via virtual tables for the correct base class. +// REQUIRES: cxxabi + #include <stdio.h> #include "utils.h" @@ -70,13 +76,17 @@ int main(int argc, char **argv) { if (argc > 1) { A *a = c; + // CFI-DIAG1: runtime error: control flow integrity check for type 'B' failed during cast to unrelated type + // CFI-DIAG1-NEXT: note: vtable is of type '{{(struct )?}}C' ((B *)a)->g(); // UB here } else { + // CFI-DIAG2: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type + // CFI-DIAG2-NEXT: note: vtable is of type '{{(struct )?}}C' B *b = c; ((A *)b)->f(); // UB here } - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/cfi/nvcall.cpp b/test/cfi/nvcall.cpp new file mode 100644 index 000000000000..04419bd9d855 --- /dev/null +++ b/test/cfi/nvcall.cpp @@ -0,0 +1,72 @@ +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx -o %t5 %s +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s + +// RUN: %clangxx_cfi_diag -o %t6 %s +// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s + +// Tests that the CFI mechanism crashes the program when making a non-virtual +// call to an object of the wrong class, by casting a pointer to such an object +// and attempting to make a call through it. + +// REQUIRES: cxxabi + +#include <stdio.h> +#include "utils.h" + +struct A { + virtual void v(); +}; + +void A::v() {} + +struct B { + void f(); + virtual void g(); +}; + +void B::f() {} +void B::g() {} + +int main() { +#ifdef B32 + break_optimization(new Deriver<B, 0>); +#endif + +#ifdef B64 + break_optimization(new Deriver<B, 0>); + break_optimization(new Deriver<B, 1>); +#endif + +#ifdef BM + break_optimization(new Deriver<B, 0>); + break_optimization(new Deriver<B, 1>); + break_optimization(new Deriver<B, 2>); +#endif + + A *a = new A; + break_optimization(a); + + // CFI: 1 + // NCFI: 1 + fprintf(stderr, "1\n"); + + // CFI-DIAG: runtime error: control flow integrity check for type 'B' failed during non-virtual call + // CFI-DIAG-NEXT: note: vtable is of type '{{(struct )?}}A' + ((B *)a)->f(); // UB here + + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} + fprintf(stderr, "2\n"); +} diff --git a/test/cfi/overwrite.cpp b/test/cfi/overwrite.cpp index d7e58d9277e9..a24e628326f3 100644 --- a/test/cfi/overwrite.cpp +++ b/test/cfi/overwrite.cpp @@ -1,23 +1,28 @@ -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t5 %s +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s + +// RUN: %clangxx_cfi_diag -o %t6 %s +// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI mechanism crashes the program when a virtual table is // replaced with a compatible table of function pointers that does not belong to // any class, by manually overwriting the virtual table of an object and // attempting to make a call through it. +// REQUIRES: cxxabi + #include <stdio.h> #include "utils.h" @@ -31,7 +36,7 @@ void foo() { fprintf(stderr, "foo\n"); } -void *fake_vtable[] = { (void *)&foo }; +void *fake_vtable[] = { 0, 0, (void *)&foo }; int main() { #ifdef B32 @@ -50,7 +55,7 @@ int main() { #endif A *a = new A; - *((void **)a) = fake_vtable; // UB here + *((void **)a) = fake_vtable + 2; // UB here break_optimization(a); // CFI: 1 @@ -59,9 +64,11 @@ int main() { // CFI-NOT: foo // NCFI: foo + // CFI-DIAG: runtime error: control flow integrity check for type 'A' failed during virtual call + // CFI-DIAG-NEXT: note: invalid vtable a->f(); - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/cfi/sibling.cpp b/test/cfi/sibling.cpp new file mode 100644 index 000000000000..a865cbc0cf6b --- /dev/null +++ b/test/cfi/sibling.cpp @@ -0,0 +1,67 @@ +// XFAIL: * + +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx -o %t5 %s +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s + +// Tests that the CFI enforcement distinguishes betwen non-overriding siblings. +// XFAILed as not implemented yet. + +#include <stdio.h> +#include "utils.h" + +struct A { + virtual void f(); +}; + +void A::f() {} + +struct B : A { + virtual void f(); +}; + +void B::f() {} + +struct C : A { +}; + +int main() { +#ifdef B32 + break_optimization(new Deriver<B, 0>); +#endif + +#ifdef B64 + break_optimization(new Deriver<B, 0>); + break_optimization(new Deriver<B, 1>); +#endif + +#ifdef BM + break_optimization(new Deriver<B, 0>); + break_optimization(new Deriver<B, 1>); + break_optimization(new Deriver<B, 2>); +#endif + + B *b = new B; + break_optimization(b); + + // CFI: 1 + // NCFI: 1 + fprintf(stderr, "1\n"); + + ((C *)b)->f(); // UB here + + // CFI-NOT: 2 + // NCFI: 2 + fprintf(stderr, "2\n"); +} diff --git a/test/cfi/simple-fail.cpp b/test/cfi/simple-fail.cpp index cf24f86e0064..c7bebb0deccc 100644 --- a/test/cfi/simple-fail.cpp +++ b/test/cfi/simple-fail.cpp @@ -1,58 +1,63 @@ -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O1 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O1 -o %t5 %s +// RUN: %expect_crash %t5 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O1 -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O1 -DB32 -o %t6 %s +// RUN: %expect_crash %t6 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O1 -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O1 -DB64 -o %t7 %s +// RUN: %expect_crash %t7 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O1 -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O1 -DBM -o %t8 %s +// RUN: %expect_crash %t8 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O2 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O2 -o %t9 %s +// RUN: %expect_crash %t9 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O2 -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O2 -DB32 -o %t10 %s +// RUN: %expect_crash %t10 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O2 -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O2 -DB64 -o %t11 %s +// RUN: %expect_crash %t11 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O2 -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O2 -DBM -o %t12 %s +// RUN: %expect_crash %t12 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O3 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O3 -o %t13 %s +// RUN: %expect_crash %t13 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O3 -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O3 -DB32 -o %t14 %s +// RUN: %expect_crash %t14 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O3 -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O3 -DB64 -o %t15 %s +// RUN: %expect_crash %t15 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -O3 -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -O3 -DBM -o %t16 %s +// RUN: %expect_crash %t16 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx_cfi_diag -o %t17 %s +// RUN: %t17 2>&1 | FileCheck --check-prefix=CFI-DIAG %s + +// RUN: %clangxx -o %t18 %s +// RUN: %t18 2>&1 | FileCheck --check-prefix=NCFI %s // Tests that the CFI mechanism crashes the program when making a virtual call // to an object of the wrong class but with a compatible vtable, by casting a // pointer to such an object and attempting to make a call through it. +// REQUIRES: cxxabi + #include <stdio.h> #include "utils.h" @@ -91,9 +96,13 @@ int main() { // NCFI: 1 fprintf(stderr, "1\n"); + // CFI-DIAG: runtime error: control flow integrity check for type 'B' failed during cast to unrelated type + // CFI-DIAG-NEXT: note: vtable is of type '{{(struct )?}}A' + // CFI-DIAG: runtime error: control flow integrity check for type 'B' failed during virtual call + // CFI-DIAG-NEXT: note: vtable is of type '{{(struct )?}}A' ((B *)a)->f(); // UB here - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } diff --git a/test/cfi/simple-pass.cpp b/test/cfi/simple-pass.cpp index 50e7d9256084..4d856eb48ce7 100644 --- a/test/cfi/simple-pass.cpp +++ b/test/cfi/simple-pass.cpp @@ -3,95 +3,119 @@ // Tests that the CFI mechanism does not crash the program when making various // kinds of valid calls involving classes with various different linkages and -// types of inheritance. +// types of inheritance, and both virtual and non-virtual member functions. #include "utils.h" struct A { virtual void f(); + void g(); }; void A::f() {} +void A::g() {} struct A2 : A { virtual void f(); + void g(); }; void A2::f() {} +void A2::g() {} struct B { virtual void f() {} + void g() {} }; struct B2 : B { virtual void f() {} + void g() {} }; namespace { struct C { virtual void f(); + void g(); }; void C::f() {} +void C::g() {} struct C2 : C { virtual void f(); + void g(); }; void C2::f() {} +void C2::g() {} struct D { virtual void f() {} + void g() {} }; struct D2 : D { virtual void f() {} + void g() {} }; } struct E { virtual void f() {} + void g() {} }; struct E2 : virtual E { virtual void f() {} + void g() {} }; int main() { A *a = new A; break_optimization(a); a->f(); + a->g(); a = new A2; break_optimization(a); a->f(); + a->g(); B *b = new B; break_optimization(b); b->f(); + b->g(); b = new B2; break_optimization(b); b->f(); + b->g(); C *c = new C; break_optimization(c); c->f(); + c->g(); c = new C2; break_optimization(c); c->f(); + c->g(); D *d = new D; break_optimization(d); d->f(); + d->g(); d = new D2; break_optimization(d); d->f(); + d->g(); E *e = new E; break_optimization(e); e->f(); + e->g(); e = new E2; break_optimization(e); e->f(); + e->g(); } diff --git a/test/cfi/vdtor.cpp b/test/cfi/vdtor.cpp index e21883c380dd..fb484ea73308 100644 --- a/test/cfi/vdtor.cpp +++ b/test/cfi/vdtor.cpp @@ -1,21 +1,26 @@ -// RUN: %clangxx_cfi -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %expect_crash %t1 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB32 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB32 -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DB64 -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DB64 -o %t3 %s +// RUN: %expect_crash %t3 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx_cfi -DBM -o %t %s -// RUN: not --crash %t 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %clangxx_cfi -DBM -o %t4 %s +// RUN: %expect_crash %t4 2>&1 | FileCheck --check-prefix=CFI %s -// RUN: %clangxx -o %t %s -// RUN: %t 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx -o %t5 %s +// RUN: %t5 2>&1 | FileCheck --check-prefix=NCFI %s + +// RUN: %clangxx_cfi_diag -o %t6 %s +// RUN: %t6 2>&1 | FileCheck --check-prefix=CFI-DIAG %s // Tests that the CFI enforcement also applies to virtual destructor calls made // via 'delete'. +// REQUIRES: cxxabi + #include <stdio.h> #include "utils.h" @@ -54,9 +59,11 @@ int main() { // NCFI: 1 fprintf(stderr, "1\n"); + // CFI-DIAG: runtime error: control flow integrity check for type 'B' failed during virtual call + // CFI-DIAG-NEXT: note: vtable is of type '{{(struct )?}}A' delete (B *)a; // UB here - // CFI-NOT: 2 - // NCFI: 2 + // CFI-NOT: {{^2$}} + // NCFI: {{^2$}} fprintf(stderr, "2\n"); } |