Index: lib/CodeGen/CGClass.cpp =================================================================== --- lib/CodeGen/CGClass.cpp +++ lib/CodeGen/CGClass.cpp @@ -2607,10 +2607,22 @@ auto TypeId = CGM.CreateCfiIdForTypeMetadata(MD); if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && TypeId) { EmitCfiSlowPathCheck(M, BitSetTest, TypeId, CastedVTable, StaticData); - } else { - EmitCheck(std::make_pair(BitSetTest, M), "cfi_check_fail", StaticData, - CastedVTable); + return; } + + if (CGM.getCodeGenOpts().SanitizeTrap.has(M)) { + EmitTrapCheck(BitSetTest); + return; + } + + llvm::Value *AllVtables = llvm::MetadataAsValue::get( + CGM.getLLVMContext(), + llvm::MDString::get(CGM.getLLVMContext(), "all-vtables")); + llvm::Value *ValidVtable = + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test), + {CastedVTable, AllVtables}); + EmitCheck(std::make_pair(BitSetTest, M), "cfi_check_fail", StaticData, + {CastedVTable, ValidVtable}); } // FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -2636,6 +2636,14 @@ Address CheckKindAddr(V, getIntAlign()); llvm::Value *CheckKind = Builder.CreateLoad(CheckKindAddr); + llvm::Value *AllVtables = llvm::MetadataAsValue::get( + CGM.getLLVMContext(), + llvm::MDString::get(CGM.getLLVMContext(), "all-vtables")); + llvm::Value *ValidVtable = Builder.CreateZExt( + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test), + {Addr, AllVtables}), + IntPtrTy); + const std::pair CheckKinds[] = { {CFITCK_VCall, SanitizerKind::CFIVCall}, {CFITCK_NVCall, SanitizerKind::CFINVCall}, @@ -2649,7 +2657,8 @@ SanitizerMask Mask = CheckKindMaskPair.second; llvm::Value *Cond = Builder.CreateICmpNE(CheckKind, llvm::ConstantInt::get(Int8Ty, Kind)); - EmitCheck(std::make_pair(Cond, Mask), "cfi_check_fail", {}, {Data, Addr}); + EmitCheck(std::make_pair(Cond, Mask), "cfi_check_fail", {}, + {Data, Addr, ValidVtable}); } FinishFunction(); @@ -3970,7 +3979,8 @@ CastedCallee, StaticData); } else { EmitCheck(std::make_pair(BitSetTest, SanitizerKind::CFIICall), - "cfi_check_fail", StaticData, CastedCallee); + "cfi_check_fail", StaticData, + {CastedCallee, llvm::UndefValue::get(IntPtrTy)}); } } Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1128,6 +1128,9 @@ /// Create a bitset entry for the given function and add it to BitsetsMD. void CreateFunctionBitSetEntry(const FunctionDecl *FD, llvm::Function *F); + /// Returns whether this module needs the "all-vtables" bitset. + bool NeedAllVtablesBitSet() const; + /// Create a bitset entry for the given vtable and add it to BitsetsMD. void CreateVTableBitSetEntry(llvm::NamedMDNode *BitsetsMD, llvm::GlobalVariable *VTable, CharUnits Offset, Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -4021,6 +4021,20 @@ return InternalId; } +/// Returns whether this module needs the "all-vtables" bitset. +bool CodeGenModule::NeedAllVtablesBitSet() const { + // Returns true if at least one of vtable-based CFI checkers is enabled and + // is not in the trapping mode. + return ((LangOpts.Sanitize.has(SanitizerKind::CFIVCall) && + !CodeGenOpts.SanitizeTrap.has(SanitizerKind::CFIVCall)) || + (LangOpts.Sanitize.has(SanitizerKind::CFINVCall) && + !CodeGenOpts.SanitizeTrap.has(SanitizerKind::CFINVCall)) || + (LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast) && + !CodeGenOpts.SanitizeTrap.has(SanitizerKind::CFIDerivedCast)) || + (LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast) && + !CodeGenOpts.SanitizeTrap.has(SanitizerKind::CFIUnrelatedCast))); +} + void CodeGenModule::CreateVTableBitSetEntry(llvm::NamedMDNode *BitsetsMD, llvm::GlobalVariable *VTable, CharUnits Offset, @@ -4043,6 +4057,17 @@ BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps2)); } } + + if (NeedAllVtablesBitSet()) { + llvm::Metadata *MD = llvm::MDString::get(getLLVMContext(), "all-vtables"); + llvm::Metadata *BitsetOps[] = { + MD, llvm::ConstantAsMetadata::get(VTable), + llvm::ConstantAsMetadata::get( + llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))}; + // Avoid adding a node to BitsetsMD twice. + if (!llvm::MDTuple::getIfExists(getLLVMContext(), BitsetOps)) + BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps)); + } } // Fills in the supplied string map with the set of target features for the Index: test/CodeGen/cfi-check-fail.c =================================================================== --- test/CodeGen/cfi-check-fail.c +++ test/CodeGen/cfi-check-fail.c @@ -22,13 +22,15 @@ // CHECK: %[[A:.*]] = bitcast i8* %[[DATA]] to { i8, { i8*, i32, i32 }, i8* }* // CHECK: %[[KINDPTR:.*]] = getelementptr {{.*}} %[[A]], i32 0, i32 0 // CHECK: %[[KIND:.*]] = load i8, i8* %[[KINDPTR]], align 4 +// CHECK: %[[VTVALID0:.*]] = call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata !"all-vtables") +// CHECK: %[[VTVALID:.*]] = zext i1 %[[VTVALID0]] to i64 // CHECK: %[[NOT_0:.*]] = icmp ne i8 %[[KIND]], 0 // CHECK: br i1 %[[NOT_0]], label %[[CONT1:.*]], label %[[HANDLE0:.*]], !prof // CHECK: [[HANDLE0]]: // CHECK: %[[DATA0:.*]] = ptrtoint i8* %[[DATA]] to i64, // CHECK: %[[ADDR0:.*]] = ptrtoint i8* %[[ADDR]] to i64, -// CHECK: call void @__ubsan_handle_cfi_check_fail(i64 %[[DATA0]], i64 %[[ADDR0]]) +// CHECK: call void @__ubsan_handle_cfi_check_fail(i64 %[[DATA0]], i64 %[[ADDR0]], i64 %[[VTVALID]]) // CHECK: br label %[[CONT1]] // CHECK: [[CONT1]]: @@ -46,7 +48,7 @@ // CHECK: [[HANDLE2]]: // CHECK: %[[DATA2:.*]] = ptrtoint i8* %[[DATA]] to i64, // CHECK: %[[ADDR2:.*]] = ptrtoint i8* %[[ADDR]] to i64, -// CHECK: call void @__ubsan_handle_cfi_check_fail_abort(i64 %[[DATA2]], i64 %[[ADDR2]]) +// CHECK: call void @__ubsan_handle_cfi_check_fail_abort(i64 %[[DATA2]], i64 %[[ADDR2]], i64 %[[VTVALID]]) // CHECK: unreachable // CHECK: [[CONT3]]: @@ -56,7 +58,7 @@ // CHECK: [[HANDLE3]]: // CHECK: %[[DATA3:.*]] = ptrtoint i8* %[[DATA]] to i64, // CHECK: %[[ADDR3:.*]] = ptrtoint i8* %[[ADDR]] to i64, -// CHECK: call void @__ubsan_handle_cfi_check_fail(i64 %[[DATA3]], i64 %[[ADDR3]]) +// CHECK: call void @__ubsan_handle_cfi_check_fail(i64 %[[DATA3]], i64 %[[ADDR3]], i64 %[[VTVALID]]) // CHECK: br label %[[CONT4]] // CHECK: [[CONT4]]: Index: test/CodeGenCXX/cfi-cast.cpp =================================================================== --- test/CodeGenCXX/cfi-cast.cpp +++ test/CodeGenCXX/cfi-cast.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-derived-cast -fsanitize-trap=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 -fsanitize-trap=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 -fsanitize-trap=cfi-unrelated-cast,cfi-cast-strict -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST-STRICT %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++11 -fsanitize=cfi-derived-cast -fsanitize-trap=cfi-derived-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-DCAST %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++11 -fsanitize=cfi-unrelated-cast -fsanitize-trap=cfi-unrelated-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++11 -fsanitize=cfi-unrelated-cast,cfi-cast-strict -fsanitize-trap=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 @@ -28,7 +28,7 @@ // CHECK-DCAST: [[CONTBB]] // CHECK-DCAST: ret - static_cast(a); + (void)static_cast(a); } // CHECK-DCAST-LABEL: define void @_Z3abrR1A @@ -42,7 +42,7 @@ // CHECK-DCAST: [[CONTBB]] // CHECK-DCAST: ret - static_cast(a); + (void)static_cast(a); } // CHECK-DCAST-LABEL: define void @_Z4abrrO1A @@ -56,7 +56,7 @@ // CHECK-DCAST: [[CONTBB]] // CHECK-DCAST: ret - static_cast(a); + (void)static_cast(a); } // CHECK-UCAST-LABEL: define void @_Z3vbpPv @@ -70,7 +70,7 @@ // CHECK-UCAST: [[CONTBB]] // CHECK-UCAST: ret - static_cast(p); + (void)static_cast(p); } // CHECK-UCAST-LABEL: define void @_Z3vbrRc @@ -84,7 +84,7 @@ // CHECK-UCAST: [[CONTBB]] // CHECK-UCAST: ret - reinterpret_cast(r); + (void)reinterpret_cast(r); } // CHECK-UCAST-LABEL: define void @_Z4vbrrOc @@ -98,7 +98,7 @@ // CHECK-UCAST: [[CONTBB]] // CHECK-UCAST: ret - reinterpret_cast(r); + (void)reinterpret_cast(r); } // CHECK-UCAST-LABEL: define void @_Z3vcpPv @@ -106,7 +106,7 @@ void vcp(void *p) { // CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A") // CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C") - static_cast(p); + (void)static_cast(p); } // CHECK-UCAST-LABEL: define void @_Z3bcpP1B @@ -114,7 +114,7 @@ void bcp(B *p) { // CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A") // CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C") - (C *)p; + (void)(C *)p; } // CHECK-UCAST-LABEL: define void @_Z8bcp_callP1B Index: test/CodeGenCXX/cfi-vcall.cpp =================================================================== --- test/CodeGenCXX/cfi-vcall.cpp +++ test/CodeGenCXX/cfi-vcall.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM --check-prefix=NDIAG %s -// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM --check-prefix=DIAG --check-prefix=DIAG-ABORT %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM --check-prefix=ITANIUM-NDIAG --check-prefix=NDIAG %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s // RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s // RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS --check-prefix=NDIAG %s @@ -55,13 +55,14 @@ // DIAG: @[[SRC:.*]] = private unnamed_addr constant [{{.*}} x i8] c"{{.*}}cfi-vcall.cpp\00", align 1 // DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [4 x i8] } { i16 -1, i16 0, [4 x i8] c"'A'\00" } -// DIAG: @[[BADTYPESTATIC:.*]] = private unnamed_addr global { i8, { [{{.*}} x i8]*, i32, i32 }, { i16, i16, [4 x i8] }* } { i8 0, { [{{.*}} x i8]*, i32, i32 } { [{{.*}} x i8]* @[[SRC]], i32 [[@LINE+21]], i32 3 }, { i16, i16, [4 x i8] }* @[[TYPE]] } +// DIAG: @[[BADTYPESTATIC:.*]] = private unnamed_addr global { i8, { [{{.*}} x i8]*, i32, i32 }, { i16, i16, [4 x i8] }* } { i8 0, { [{{.*}} x i8]*, i32, i32 } { [{{.*}} x i8]* @[[SRC]], i32 [[@LINE+23]], i32 3 }, { i16, i16, [4 x i8] }* @[[TYPE]] } // ITANIUM: define void @_Z2afP1A // MS: define void @"\01?af@@YAXPEAUA@@@Z" void af(A *a) { // ITANIUM: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"_ZTS1A") // MS: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"?AUA@@") + // DIAG-NEXT: [[VTVALID0:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT]], metadata !"all-vtables") // CHECK-NEXT: br i1 [[P]], label %[[CONTBB:[^ ,]*]], label %[[TRAPBB:[^ ,]*]] // CHECK-NEXT: {{^$}} @@ -69,9 +70,10 @@ // NDIAG-NEXT: call void @llvm.trap() // NDIAG-NEXT: unreachable // DIAG-NEXT: [[VTINT:%[^ ]*]] = ptrtoint i8* [[VT]] to i64 - // DIAG-ABORT-NEXT: call void @__ubsan_handle_cfi_check_fail_abort(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]]) + // DIAG-NEXT: [[VTVALID:%[^ ]*]] = zext i1 [[VTVALID0]] to i64 + // DIAG-ABORT-NEXT: call void @__ubsan_handle_cfi_check_fail_abort(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]]) // DIAG-ABORT-NEXT: unreachable - // DIAG-RECOVER-NEXT: call void @__ubsan_handle_cfi_check_fail(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]]) + // DIAG-RECOVER-NEXT: call void @__ubsan_handle_cfi_check_fail(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]]) // DIAG-RECOVER-NEXT: br label %[[CONTBB]] // CHECK: [[CONTBB]] @@ -157,20 +159,28 @@ } -// Check for the expected number of elements (9 or 15 respectively). -// MS: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){8}]]} -// ITANIUM: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){14}]]} +// Check for the expected number of elements (15 or 23 respectively). +// MS-NDIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){9}]]} +// MS-DIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){15}]]} +// ITANIUM-NDIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){14}]]} +// ITANIUM-DIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){23}]]} // ITANIUM-DAG: !{!"_ZTS1A", [3 x i8*]* @_ZTV1A, i64 16} +// ITANIUM-DIAG-DAG: !{!"all-vtables", [3 x i8*]* @_ZTV1A, i64 16} // ITANIUM-DAG: !{!"_ZTS1A", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32} +// ITANIUM-DIAG-DAG: !{!"all-vtables", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32} // ITANIUM-DAG: !{!"_ZTS1B", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32} // ITANIUM-DAG: !{!"_ZTS1A", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 64} +// ITANIUM-DIAG-DAG: !{!"all-vtables", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 64} // ITANIUM-DAG: !{!"_ZTS1C", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 32} // ITANIUM-DAG: !{!"_ZTS1A", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32} +// ITANIUM-DIAG-DAG: !{!"all-vtables", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32} // ITANIUM-DAG: !{!"_ZTS1B", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32} // ITANIUM-DAG: !{!"_ZTS1C", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 88} +// ITANIUM-DIAG-DAG: !{!"all-vtables", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 88} // ITANIUM-DAG: !{![[DTYPE]], [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32} // ITANIUM-DAG: !{!"_ZTS1A", [7 x i8*]* @_ZTV1B, i64 32} +// ITANIUM-DIAG-DAG: !{!"all-vtables", [7 x i8*]* @_ZTV1B, i64 32} // ITANIUM-DAG: !{!"_ZTS1B", [7 x i8*]* @_ZTV1B, i64 32} // ITANIUM-DAG: !{!"_ZTS1A", [5 x i8*]* @_ZTV1C, i64 32} // ITANIUM-DAG: !{!"_ZTS1C", [5 x i8*]* @_ZTV1C, i64 32} @@ -178,11 +188,18 @@ // ITANIUM-DAG: !{!{{[0-9]+}}, [3 x i8*]* @_ZTVZ3foovE2FA, i64 16} // MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTA]], i64 8} +// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTA]], i64 8} // MS-DAG: !{!"?AUB@@", [3 x i8*]* @[[VTB]], i64 8} +// MS-DIAG-DAG: !{!"all-vtables", [3 x i8*]* @[[VTB]], i64 8} // MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinB]], i64 8} +// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTAinB]], i64 8} // MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinC]], i64 8} +// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTAinC]], i64 8} // MS-DAG: !{!"?AUB@@", [3 x i8*]* @[[VTBinD]], i64 8} +// MS-DIAG-DAG: !{!"all-vtables", [3 x i8*]* @[[VTBinD]], i64 8} // MS-DAG: !{![[DTYPE]], [3 x i8*]* @[[VTBinD]], i64 8} // MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinBinD]], i64 8} +// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTAinBinD]], i64 8} // MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTFA]], i64 8} +// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTFA]], i64 8} // MS-DAG: !{!{{[0-9]+}}, [2 x i8*]* @[[VTFA]], i64 8}