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
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<int, SanitizerMask> CheckKinds[] = {
{CFITCK_VCall, SanitizerKind::CFIVCall},
{CFITCK_NVCall, SanitizerKind::CFINVCall},
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();
CastedCallee, StaticData);
} else {
EmitCheck(std::make_pair(BitSetTest, SanitizerKind::CFIICall),
- "cfi_check_fail", StaticData, CastedCallee);
+ "cfi_check_fail", StaticData,
+ {CastedCallee, llvm::UndefValue::get(IntPtrTy)});
}
}
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,
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
/// 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,
// 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]]:
// 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]]:
// 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]]:
-// 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
// CHECK-DCAST: [[CONTBB]]
// CHECK-DCAST: ret
- static_cast<B*>(a);
+ (void)static_cast<B*>(a);
}
// CHECK-DCAST-LABEL: define void @_Z3abrR1A
// CHECK-DCAST: [[CONTBB]]
// CHECK-DCAST: ret
- static_cast<B&>(a);
+ (void)static_cast<B&>(a);
}
// CHECK-DCAST-LABEL: define void @_Z4abrrO1A
// CHECK-DCAST: [[CONTBB]]
// CHECK-DCAST: ret
- static_cast<B&&>(a);
+ (void)static_cast<B&&>(a);
}
// CHECK-UCAST-LABEL: define void @_Z3vbpPv
// CHECK-UCAST: [[CONTBB]]
// CHECK-UCAST: ret
- static_cast<B*>(p);
+ (void)static_cast<B*>(p);
}
// CHECK-UCAST-LABEL: define void @_Z3vbrRc
// CHECK-UCAST: [[CONTBB]]
// CHECK-UCAST: ret
- reinterpret_cast<B&>(r);
+ (void)reinterpret_cast<B&>(r);
}
// CHECK-UCAST-LABEL: define void @_Z4vbrrOc
// CHECK-UCAST: [[CONTBB]]
// CHECK-UCAST: ret
- reinterpret_cast<B&&>(r);
+ (void)reinterpret_cast<B&&>(r);
}
// CHECK-UCAST-LABEL: define void @_Z3vcpPv
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<C*>(p);
+ (void)static_cast<C*>(p);
}
// CHECK-UCAST-LABEL: define void @_Z3bcpP1B
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
-// 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
// 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: {{^$}}
// 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]]
}
-// 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}
// 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}