summaryrefslogtreecommitdiff
path: root/test/cfi
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2016-02-03 22:19:04 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2016-02-03 22:19:04 +0000
commita29fa41fc3ca1602870b790560b468c916316489 (patch)
tree8e2f4436895363d5afdcafb70770c69f8994ee60 /test/cfi
parent5f5df3d90b47630c35c54e455ed83a02438db07d (diff)
[cfi] Safe handling of unaddressable vtable pointers (compiler-rt).
Avoid crashing when printing diagnostics for vtable-related CFI errors. In diagnostic mode, the frontend does an additional check of the vtable pointer against the set of all known vtable addresses and lets the runtime handler know if it is safe to inspect the vtable. http://reviews.llvm.org/D16824 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@259717 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/cfi')
-rw-r--r--test/cfi/cross-dso/target_out_of_bounds.cpp58
-rw-r--r--test/cfi/target_uninstrumented.cpp44
2 files changed, 89 insertions, 13 deletions
diff --git a/test/cfi/cross-dso/target_out_of_bounds.cpp b/test/cfi/cross-dso/target_out_of_bounds.cpp
index fbd664bce..6353f030a 100644
--- a/test/cfi/cross-dso/target_out_of_bounds.cpp
+++ b/test/cfi/cross-dso/target_out_of_bounds.cpp
@@ -1,5 +1,12 @@
-// RUN: %clangxx_cfi_dso_diag %s -o %t
-// RUN: %expect_crash %t 2>&1 | FileCheck %s
+// RUN: %clangxx_cfi_dso_diag -std=c++11 %s -o %t
+// RUN: %t zero 2>&1 | FileCheck --check-prefix=CHECK-ZERO %s
+// RUN: %t unaddressable 2>&1 | FileCheck --check-prefix=CHECK-UNADDR %s
+// RUN: %t 2>&1 | FileCheck --check-prefix=CHECK-TYPEINFO %s
+
+// RUN: %clangxx_cfi_diag -std=c++11 %s -o %t2
+// RUN: %t2 zero 2>&1 | FileCheck --check-prefix=CHECK-ZERO %s
+// RUN: %t2 unaddressable 2>&1 | FileCheck --check-prefix=CHECK-UNADDR %s
+// RUN: %t2 2>&1 | FileCheck --check-prefix=CHECK-TYPEINFO %s
// REQUIRES: cxxabi
@@ -7,6 +14,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
struct A {
virtual void f();
@@ -15,18 +23,42 @@ struct A {
void A::f() {}
int main(int argc, char *argv[]) {
- // Create an object with a vtable outside of any known DSO, but still in an
- // addressable area. Current implementation of handlers in UBSan is not robust
- // enough to handle unaddressable vtables. TODO: fix this.
- void *empty = calloc(1, 128);
- uintptr_t v = (uintptr_t)empty + 64;
char *volatile p = reinterpret_cast<char *>(new A());
- for (uintptr_t *q = (uintptr_t *)p; q < (uintptr_t *)(p + sizeof(A)); ++q)
- *q = v;
+ if (argc > 1 && strcmp(argv[1], "unaddressable") == 0) {
+ void *vtable = mmap(nullptr, 4096, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ // Create an object with a vtable in an unaddressable memory region.
+ *(uintptr_t *)p = (uintptr_t)vtable + 64;
+ // CHECK-UNADDR: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-UNADDR: note: invalid vtable
+ // CHECK-UNADDR: <memory cannot be printed>
+ // CHECK-UNADDR: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-UNADDR: note: invalid vtable
+ // CHECK-UNADDR: <memory cannot be printed>
+ } else if (argc > 1 && strcmp(argv[1], "zero") == 0) {
+ // Create an object with a vtable outside of any known DSO, but still in an
+ // addressable area.
+ void *vtable = calloc(1, 128);
+ *(uintptr_t *)p = (uintptr_t)vtable + 64;
+ // CHECK-ZERO: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-ZERO: note: invalid vtable
+ // CHECK-ZERO: 00 00 00 00 00 00 00 00
+ // CHECK-ZERO: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-ZERO: note: invalid vtable
+ // CHECK-ZERO: 00 00 00 00 00 00 00 00
+ } else {
+ // Create an object with a seemingly fine vtable, but with an unaddressable
+ // typeinfo pointer.
+ void *vtable = calloc(1, 128);
+ memset(vtable, 0xFE, 128);
+ *(uintptr_t *)p = (uintptr_t)vtable + 64;
+ // CHECK-TYPEINFO: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-TYPEINFO: note: invalid vtable
+ // CHECK-TYPEINFO: fe fe fe fe fe fe fe fe
+ // CHECK-TYPEINFO: runtime error: control flow integrity check for type 'A' failed during cast
+ // CHECK-TYPEINFO: note: invalid vtable
+ // CHECK-TYPEINFO: fe fe fe fe fe fe fe fe
+ }
- // CHECK: runtime error: control flow integrity check for type 'A' failed during cast
A *volatile pa = reinterpret_cast<A *>(p);
-
- // CHECK: untime error: control flow integrity check for type 'A' failed during virtual call
- pa->f();
+ pa = reinterpret_cast<A *>(p);
}
diff --git a/test/cfi/target_uninstrumented.cpp b/test/cfi/target_uninstrumented.cpp
new file mode 100644
index 000000000..2ec2b5bbc
--- /dev/null
+++ b/test/cfi/target_uninstrumented.cpp
@@ -0,0 +1,44 @@
+// RUN: %clangxx -g -DSHARED_LIB %s -fPIC -shared -o %T/target_uninstrumented-so.so
+// RUN: %clangxx_cfi_diag -g %s -o %t %T/target_uninstrumented-so.so
+// RUN: %t 2>&1 | FileCheck %s
+
+// REQUIRES: cxxabi
+
+#include <stdio.h>
+#include <string.h>
+
+struct A {
+ virtual void f();
+};
+
+void *create_B();
+
+#ifdef SHARED_LIB
+
+struct B {
+ virtual void f();
+};
+void B::f() {}
+
+void *create_B() {
+ return (void *)(new B());
+}
+
+#else
+
+void A::f() {}
+
+int main(int argc, char *argv[]) {
+ void *p = create_B();
+ // CHECK: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type
+ // CHECK: invalid vtable in module {{.*}}target_uninstrumented-so.so
+ A *a = (A *)p;
+ memset(p, 0, sizeof(A));
+ // CHECK: runtime error: control flow integrity check for type 'A' failed during cast to unrelated type
+ // CHECK-NOT: invalid vtable in module
+ // CHECK: invalid vtable
+ a = (A *)p;
+ // CHECK: done
+ fprintf(stderr, "done %p\n", a);
+}
+#endif