Files
clang-p2996/clang/test/CodeGenCXX/cfi-cast.cpp
Peter Collingbourne d2926c91d5 Implement bad cast checks using control flow integrity information.
This scheme checks that pointer and lvalue casts are made to an object of
the correct dynamic type; that is, the dynamic type of the object must be
a derived class of the pointee type of the cast. The checks are currently
only introduced where the class being casted to is a polymorphic class.

Differential Revision: http://reviews.llvm.org/D8312

llvm-svn: 232241
2015-03-14 02:42:25 +00:00

110 lines
3.6 KiB
C++

// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-derived-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-DCAST %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-unrelated-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-unrelated-cast,cfi-cast-strict -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST-STRICT %s
// In this test the main thing we are searching for is something like
// 'metadata !"1B"' where "1B" is the mangled name of the class we are
// casting to (or maybe its base class in non-strict mode).
struct A {
virtual void f();
};
struct B : A {
virtual void f();
};
struct C : A {};
// CHECK-DCAST-LABEL: define void @_Z3abpP1A
void abp(A *a) {
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ]*]]
// CHECK-DCAST: [[TRAPBB]]
// CHECK-DCAST-NEXT: call void @llvm.trap()
// CHECK-DCAST-NEXT: unreachable
// CHECK-DCAST: [[CONTBB]]
// CHECK-DCAST: ret
static_cast<B*>(a);
}
// CHECK-DCAST-LABEL: define void @_Z3abrR1A
void abr(A &a) {
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ]*]]
// CHECK-DCAST: [[TRAPBB]]
// CHECK-DCAST-NEXT: call void @llvm.trap()
// CHECK-DCAST-NEXT: unreachable
// CHECK-DCAST: [[CONTBB]]
// CHECK-DCAST: ret
static_cast<B&>(a);
}
// CHECK-DCAST-LABEL: define void @_Z4abrrO1A
void abrr(A &&a) {
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ]*]]
// CHECK-DCAST: [[TRAPBB]]
// CHECK-DCAST-NEXT: call void @llvm.trap()
// CHECK-DCAST-NEXT: unreachable
// CHECK-DCAST: [[CONTBB]]
// CHECK-DCAST: ret
static_cast<B&&>(a);
}
// CHECK-UCAST-LABEL: define void @_Z3vbpPv
void vbp(void *p) {
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ]*]]
// CHECK-UCAST: [[TRAPBB]]
// CHECK-UCAST-NEXT: call void @llvm.trap()
// CHECK-UCAST-NEXT: unreachable
// CHECK-UCAST: [[CONTBB]]
// CHECK-UCAST: ret
static_cast<B*>(p);
}
// CHECK-UCAST-LABEL: define void @_Z3vbrRc
void vbr(char &r) {
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ]*]]
// CHECK-UCAST: [[TRAPBB]]
// CHECK-UCAST-NEXT: call void @llvm.trap()
// CHECK-UCAST-NEXT: unreachable
// CHECK-UCAST: [[CONTBB]]
// CHECK-UCAST: ret
reinterpret_cast<B&>(r);
}
// CHECK-UCAST-LABEL: define void @_Z4vbrrOc
void vbrr(char &&r) {
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ]*]]
// CHECK-UCAST: [[TRAPBB]]
// CHECK-UCAST-NEXT: call void @llvm.trap()
// CHECK-UCAST-NEXT: unreachable
// CHECK-UCAST: [[CONTBB]]
// CHECK-UCAST: ret
reinterpret_cast<B&&>(r);
}
// CHECK-UCAST-LABEL: define void @_Z3vcpPv
// CHECK-UCAST-STRICT-LABEL: define void @_Z3vcpPv
void vcp(void *p) {
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1A")
// CHECK-UCAST-STRICT: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1C")
static_cast<C*>(p);
}