| // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=alignment | FileCheck %s -check-prefixes=ALIGN,COMMON |
| // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s -check-prefixes=NULL,COMMON |
| // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=object-size | FileCheck %s -check-prefixes=OBJSIZE,COMMON |
| // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null,vptr | FileCheck %s -check-prefixes=VPTR |
| // RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=vptr | FileCheck %s -check-prefixes=VPTR_NO_NULL |
| |
| struct A { |
| // COMMON-LABEL: define linkonce_odr void @_ZN1A10do_nothingEv |
| void do_nothing() { |
| // ALIGN-NOT: ptrtoint %struct.A* %{{.*}} to i64, !nosanitize |
| |
| // NULL: icmp ne %struct.A* %{{.*}}, null, !nosanitize |
| |
| // OBJSIZE-NOT: call i64 @llvm.objectsize |
| } |
| }; |
| |
| struct B { |
| int x; |
| |
| // COMMON-LABEL: define linkonce_odr void @_ZN1B10do_nothingEv |
| void do_nothing() { |
| // ALIGN: ptrtoint %struct.B* %{{.*}} to i64, !nosanitize |
| // ALIGN: and i64 %{{.*}}, 3, !nosanitize |
| |
| // NULL: icmp ne %struct.B* %{{.*}}, null, !nosanitize |
| |
| // OBJSIZE-NOT: call i64 @llvm.objectsize |
| // OBJSIZE: ret void |
| } |
| }; |
| |
| struct Animal { |
| virtual const char *speak() = 0; |
| }; |
| |
| struct Cat : Animal { |
| const char *speak() override { return "meow"; } |
| }; |
| |
| struct Dog : Animal { |
| const char *speak() override { return "woof"; } |
| }; |
| |
| // VPTR-LABEL: define void @_Z12invalid_castP3Cat |
| void invalid_cast(Cat *cat = nullptr) { |
| // If -fsanitize=null is available, we'll reuse its check: |
| // |
| // VPTR: [[ICMP:%.*]] = icmp ne %struct.Dog* {{.*}}, null |
| // VPTR-NEXT: br i1 [[ICMP]] |
| // VPTR: call void @__ubsan_handle_type_mismatch |
| // VPTR-NOT: icmp ne %struct.Dog* {{.*}}, null |
| // VPTR: br i1 [[ICMP]] |
| // VPTR: call void @__ubsan_handle_dynamic_type_cache_miss |
| // |
| // Fall back to the vptr sanitizer's null check when -fsanitize=null isn't |
| // available. |
| // |
| // VPTR_NO_NULL-NOT: call void @__ubsan_handle_type_mismatch |
| // VPTR_NO_NULL: [[ICMP:%.*]] = icmp ne %struct.Dog* {{.*}}, null |
| // VPTR_NO_NULL-NEXT: br i1 [[ICMP]] |
| // VPTR_NO_NULL: call void @__ubsan_handle_dynamic_type_cache_miss |
| auto *badDog = reinterpret_cast<Dog *>(cat); |
| badDog->speak(); |
| } |
| |
| // VPTR_NO_NULL-LABEL: define void @_Z13invalid_cast2v |
| void invalid_cast2() { |
| // We've got a pointer to an alloca, so there's no run-time null check needed. |
| // VPTR_NO_NULL-NOT: call void @__ubsan_handle_type_mismatch |
| // VPTR_NO_NULL: call void @__ubsan_handle_dynamic_type_cache_miss |
| Cat cat; |
| cat.speak(); |
| } |
| |
| int main() { |
| A a; |
| a.do_nothing(); |
| |
| B b; |
| b.do_nothing(); |
| |
| invalid_cast(); |
| return 0; |
| } |