forked from OSchip/llvm-project
Implement diagnostic mode for -fsanitize=cfi*, -fsanitize=cfi-diag.
This causes programs compiled with this flag to print a diagnostic when a control flow integrity check fails instead of aborting. Diagnostics are printed using UBSan's runtime library. The main motivation of this feature over -fsanitize=vptr is fidelity with the -fsanitize=cfi implementation: the diagnostics are printed under exactly the same conditions as those which would cause -fsanitize=cfi to abort the program. This means that the same restrictions apply regarding compiling all translation units with -fsanitize=cfi, cross-DSO virtual calls are forbidden, etc. Differential Revision: http://reviews.llvm.org/D10268 llvm-svn: 240109
This commit is contained in:
parent
2a567835d1
commit
6708c4a176
|
@ -1108,10 +1108,12 @@ are listed below.
|
|||
the binary size increase caused by the sanitizer runtime is a concern.
|
||||
|
||||
This flag is only compatible with ``local-bounds``,
|
||||
``unsigned-integer-overflow`` and sanitizers in the ``undefined``
|
||||
group other than ``vptr``. If this flag is supplied together with
|
||||
``-fsanitize=undefined``, the ``vptr`` sanitizer will be implicitly
|
||||
disabled.
|
||||
``unsigned-integer-overflow``, sanitizers in the ``cfi`` group and
|
||||
sanitizers in the ``undefined`` group other than ``vptr``. If this flag
|
||||
is supplied together with ``-fsanitize=undefined``, the ``vptr`` sanitizer
|
||||
will be implicitly disabled.
|
||||
|
||||
This flag is enabled by default for sanitizers in the ``cfi`` group.
|
||||
|
||||
**-f[no-]sanitize-coverage=[type,features,...]**
|
||||
|
||||
|
|
|
@ -366,7 +366,8 @@ public:
|
|||
virtual llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF,
|
||||
GlobalDecl GD,
|
||||
llvm::Value *This,
|
||||
llvm::Type *Ty) = 0;
|
||||
llvm::Type *Ty,
|
||||
SourceLocation Loc) = 0;
|
||||
|
||||
/// Emit the ABI-specific virtual destructor call.
|
||||
virtual llvm::Value *
|
||||
|
|
|
@ -2134,17 +2134,21 @@ LeastDerivedClassWithSameLayout(const CXXRecordDecl *RD) {
|
|||
}
|
||||
|
||||
void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXMethodDecl *MD,
|
||||
llvm::Value *VTable) {
|
||||
llvm::Value *VTable,
|
||||
CFITypeCheckKind TCK,
|
||||
SourceLocation Loc) {
|
||||
const CXXRecordDecl *ClassDecl = MD->getParent();
|
||||
if (!SanOpts.has(SanitizerKind::CFICastStrict))
|
||||
ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
|
||||
|
||||
EmitVTablePtrCheck(ClassDecl, VTable);
|
||||
EmitVTablePtrCheck(ClassDecl, VTable, TCK, Loc);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T,
|
||||
llvm::Value *Derived,
|
||||
bool MayBeNull) {
|
||||
bool MayBeNull,
|
||||
CFITypeCheckKind TCK,
|
||||
SourceLocation Loc) {
|
||||
if (!getLangOpts().CPlusPlus)
|
||||
return;
|
||||
|
||||
|
@ -2184,7 +2188,7 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T,
|
|||
}
|
||||
|
||||
llvm::Value *VTable = GetVTablePtr(Derived, Int8PtrTy);
|
||||
EmitVTablePtrCheck(ClassDecl, VTable);
|
||||
EmitVTablePtrCheck(ClassDecl, VTable, TCK, Loc);
|
||||
|
||||
if (MayBeNull) {
|
||||
Builder.CreateBr(ContBlock);
|
||||
|
@ -2193,11 +2197,15 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T,
|
|||
}
|
||||
|
||||
void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
|
||||
llvm::Value *VTable) {
|
||||
llvm::Value *VTable,
|
||||
CFITypeCheckKind TCK,
|
||||
SourceLocation Loc) {
|
||||
// FIXME: Add blacklisting scheme.
|
||||
if (RD->isInStdNamespace())
|
||||
return;
|
||||
|
||||
SanitizerScope SanScope(this);
|
||||
|
||||
std::string OutName;
|
||||
llvm::raw_string_ostream Out(OutName);
|
||||
CGM.getCXXABI().getMangleContext().mangleCXXVTableBitSet(RD, Out);
|
||||
|
@ -2205,20 +2213,34 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
|
|||
llvm::Value *BitSetName = llvm::MetadataAsValue::get(
|
||||
getLLVMContext(), llvm::MDString::get(getLLVMContext(), Out.str()));
|
||||
|
||||
llvm::Value *BitSetTest = Builder.CreateCall(
|
||||
CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
|
||||
{Builder.CreateBitCast(VTable, CGM.Int8PtrTy), BitSetName});
|
||||
llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
|
||||
llvm::Value *BitSetTest =
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
|
||||
{CastedVTable, BitSetName});
|
||||
|
||||
llvm::BasicBlock *ContBlock = createBasicBlock("vtable.check.cont");
|
||||
llvm::BasicBlock *TrapBlock = createBasicBlock("vtable.check.trap");
|
||||
SanitizerMask M;
|
||||
switch (TCK) {
|
||||
case CFITCK_VCall:
|
||||
M = SanitizerKind::CFIVCall;
|
||||
break;
|
||||
case CFITCK_NVCall:
|
||||
M = SanitizerKind::CFINVCall;
|
||||
break;
|
||||
case CFITCK_DerivedCast:
|
||||
M = SanitizerKind::CFIDerivedCast;
|
||||
break;
|
||||
case CFITCK_UnrelatedCast:
|
||||
M = SanitizerKind::CFIUnrelatedCast;
|
||||
break;
|
||||
}
|
||||
|
||||
Builder.CreateCondBr(BitSetTest, ContBlock, TrapBlock);
|
||||
|
||||
EmitBlock(TrapBlock);
|
||||
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap), {});
|
||||
Builder.CreateUnreachable();
|
||||
|
||||
EmitBlock(ContBlock);
|
||||
llvm::Constant *StaticData[] = {
|
||||
EmitCheckSourceLocation(Loc),
|
||||
EmitCheckTypeDescriptor(QualType(RD->getTypeForDecl(), 0)),
|
||||
llvm::ConstantInt::get(Int8Ty, TCK),
|
||||
};
|
||||
EmitCheck(std::make_pair(BitSetTest, M), "cfi_bad_type", StaticData,
|
||||
CastedVTable);
|
||||
}
|
||||
|
||||
// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do
|
||||
|
|
|
@ -3035,7 +3035,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
|
|||
Derived, E->getType());
|
||||
|
||||
if (SanOpts.has(SanitizerKind::CFIDerivedCast))
|
||||
EmitVTablePtrCheckForCast(E->getType(), Derived, /*MayBeNull=*/false);
|
||||
EmitVTablePtrCheckForCast(E->getType(), Derived, /*MayBeNull=*/false,
|
||||
CFITCK_DerivedCast, E->getLocStart());
|
||||
|
||||
return MakeAddrLValue(Derived, E->getType());
|
||||
}
|
||||
|
@ -3048,7 +3049,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
|
|||
ConvertType(CE->getTypeAsWritten()));
|
||||
|
||||
if (SanOpts.has(SanitizerKind::CFIUnrelatedCast))
|
||||
EmitVTablePtrCheckForCast(E->getType(), V, /*MayBeNull=*/false);
|
||||
EmitVTablePtrCheckForCast(E->getType(), V, /*MayBeNull=*/false,
|
||||
CFITCK_UnrelatedCast, E->getLocStart());
|
||||
|
||||
return MakeAddrLValue(V, E->getType());
|
||||
}
|
||||
|
|
|
@ -254,12 +254,13 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
|
|||
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
|
||||
Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty);
|
||||
} else if (UseVirtualCall) {
|
||||
Callee = CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, Ty);
|
||||
Callee = CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, Ty,
|
||||
CE->getLocStart());
|
||||
} else {
|
||||
if (SanOpts.has(SanitizerKind::CFINVCall) &&
|
||||
MD->getParent()->isDynamicClass()) {
|
||||
llvm::Value *VTable = GetVTablePtr(This, Int8PtrTy);
|
||||
EmitVTablePtrCheckForCall(MD, VTable);
|
||||
EmitVTablePtrCheckForCall(MD, VTable, CFITCK_NVCall, CE->getLocStart());
|
||||
}
|
||||
|
||||
if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier)
|
||||
|
|
|
@ -1386,7 +1386,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
|
|||
if (CGF.SanOpts.has(SanitizerKind::CFIUnrelatedCast)) {
|
||||
if (auto PT = DestTy->getAs<PointerType>())
|
||||
CGF.EmitVTablePtrCheckForCast(PT->getPointeeType(), Src,
|
||||
/*MayBeNull=*/true);
|
||||
/*MayBeNull=*/true,
|
||||
CodeGenFunction::CFITCK_UnrelatedCast,
|
||||
CE->getLocStart());
|
||||
}
|
||||
|
||||
return Builder.CreateBitCast(Src, DstTy);
|
||||
|
@ -1420,7 +1422,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
|
|||
|
||||
if (CGF.SanOpts.has(SanitizerKind::CFIDerivedCast))
|
||||
CGF.EmitVTablePtrCheckForCast(DestTy->getPointeeType(), Derived,
|
||||
/*MayBeNull=*/true);
|
||||
/*MayBeNull=*/true,
|
||||
CodeGenFunction::CFITCK_DerivedCast,
|
||||
CE->getLocStart());
|
||||
|
||||
return Derived;
|
||||
}
|
||||
|
|
|
@ -1311,19 +1311,29 @@ public:
|
|||
/// to by This.
|
||||
llvm::Value *GetVTablePtr(llvm::Value *This, llvm::Type *Ty);
|
||||
|
||||
enum CFITypeCheckKind {
|
||||
CFITCK_VCall,
|
||||
CFITCK_NVCall,
|
||||
CFITCK_DerivedCast,
|
||||
CFITCK_UnrelatedCast,
|
||||
};
|
||||
|
||||
/// \brief Derived is the presumed address of an object of type T after a
|
||||
/// cast. If T is a polymorphic class type, emit a check that the virtual
|
||||
/// table for Derived belongs to a class derived from T.
|
||||
void EmitVTablePtrCheckForCast(QualType T, llvm::Value *Derived,
|
||||
bool MayBeNull);
|
||||
bool MayBeNull, CFITypeCheckKind TCK,
|
||||
SourceLocation Loc);
|
||||
|
||||
/// EmitVTablePtrCheckForCall - Virtual method MD is being called via VTable.
|
||||
/// If vptr CFI is enabled, emit a check that VTable is valid.
|
||||
void EmitVTablePtrCheckForCall(const CXXMethodDecl *MD, llvm::Value *VTable);
|
||||
void EmitVTablePtrCheckForCall(const CXXMethodDecl *MD, llvm::Value *VTable,
|
||||
CFITypeCheckKind TCK, SourceLocation Loc);
|
||||
|
||||
/// EmitVTablePtrCheck - Emit a check that VTable is a valid virtual table for
|
||||
/// RD using llvm.bitset.test.
|
||||
void EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable);
|
||||
void EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable,
|
||||
CFITypeCheckKind TCK, SourceLocation Loc);
|
||||
|
||||
/// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
|
||||
/// expr can be devirtualized.
|
||||
|
|
|
@ -204,7 +204,8 @@ public:
|
|||
|
||||
llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD,
|
||||
llvm::Value *This,
|
||||
llvm::Type *Ty) override;
|
||||
llvm::Type *Ty,
|
||||
SourceLocation Loc) override;
|
||||
|
||||
llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
|
@ -1439,13 +1440,15 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
|
|||
llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
|
||||
GlobalDecl GD,
|
||||
llvm::Value *This,
|
||||
llvm::Type *Ty) {
|
||||
llvm::Type *Ty,
|
||||
SourceLocation Loc) {
|
||||
GD = GD.getCanonicalDecl();
|
||||
Ty = Ty->getPointerTo()->getPointerTo();
|
||||
llvm::Value *VTable = CGF.GetVTablePtr(This, Ty);
|
||||
|
||||
if (CGF.SanOpts.has(SanitizerKind::CFIVCall))
|
||||
CGF.EmitVTablePtrCheckForCall(cast<CXXMethodDecl>(GD.getDecl()), VTable);
|
||||
CGF.EmitVTablePtrCheckForCall(cast<CXXMethodDecl>(GD.getDecl()), VTable,
|
||||
CodeGenFunction::CFITCK_VCall, Loc);
|
||||
|
||||
uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
|
||||
llvm::Value *VFuncPtr =
|
||||
|
@ -1463,7 +1466,8 @@ llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall(
|
|||
Dtor, getFromDtorType(DtorType));
|
||||
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
|
||||
llvm::Value *Callee =
|
||||
getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, DtorType), This, Ty);
|
||||
getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, DtorType), This, Ty,
|
||||
CE ? CE->getLocStart() : SourceLocation());
|
||||
|
||||
CGF.EmitCXXMemberOrOperatorCall(Dtor, Callee, ReturnValueSlot(), This,
|
||||
/*ImplicitParam=*/nullptr, QualType(), CE);
|
||||
|
|
|
@ -221,8 +221,8 @@ public:
|
|||
CharUnits VPtrOffset) override;
|
||||
|
||||
llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD,
|
||||
llvm::Value *This,
|
||||
llvm::Type *Ty) override;
|
||||
llvm::Value *This, llvm::Type *Ty,
|
||||
SourceLocation Loc) override;
|
||||
|
||||
llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
|
@ -1588,7 +1588,8 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
|
|||
llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
|
||||
GlobalDecl GD,
|
||||
llvm::Value *This,
|
||||
llvm::Type *Ty) {
|
||||
llvm::Type *Ty,
|
||||
SourceLocation Loc) {
|
||||
GD = GD.getCanonicalDecl();
|
||||
CGBuilderTy &Builder = CGF.Builder;
|
||||
|
||||
|
@ -1616,7 +1617,8 @@ llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall(
|
|||
const CGFunctionInfo *FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration(
|
||||
Dtor, StructorType::Deleting);
|
||||
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
|
||||
llvm::Value *Callee = getVirtualFunctionPointer(CGF, GD, This, Ty);
|
||||
llvm::Value *Callee = getVirtualFunctionPointer(
|
||||
CGF, GD, This, Ty, CE ? CE->getLocStart() : SourceLocation());
|
||||
|
||||
ASTContext &Context = getContext();
|
||||
llvm::Value *ImplicitParam = llvm::ConstantInt::get(
|
||||
|
|
|
@ -25,7 +25,7 @@ using namespace clang::driver;
|
|||
using namespace llvm::opt;
|
||||
|
||||
enum : SanitizerMask {
|
||||
NeedsUbsanRt = Undefined | Integer,
|
||||
NeedsUbsanRt = Undefined | Integer | CFI,
|
||||
NotAllowedWithTrap = Vptr,
|
||||
RequiresPIE = Memory | DataFlow,
|
||||
NeedsUnwindTables = Address | Thread | Memory | DataFlow,
|
||||
|
@ -35,7 +35,8 @@ enum : SanitizerMask {
|
|||
LegacyFsanitizeRecoverMask = Undefined | Integer,
|
||||
NeedsLTO = CFI,
|
||||
TrappingSupported =
|
||||
(Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds,
|
||||
(Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds | CFI,
|
||||
TrappingDefault = CFI,
|
||||
};
|
||||
|
||||
enum CoverageFeature {
|
||||
|
@ -166,6 +167,9 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
|
|||
}
|
||||
}
|
||||
|
||||
// Apply default trapping behavior.
|
||||
TrappingKinds |= TrappingDefault & ~TrapRemove;
|
||||
|
||||
return TrappingKinds;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 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
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
@ -19,7 +19,7 @@ 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-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-DCAST: [[TRAPBB]]
|
||||
// CHECK-DCAST-NEXT: call void @llvm.trap()
|
||||
|
@ -33,7 +33,7 @@ void abp(A *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-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-DCAST: [[TRAPBB]]
|
||||
// CHECK-DCAST-NEXT: call void @llvm.trap()
|
||||
|
@ -47,7 +47,7 @@ void abr(A &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-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-DCAST: [[TRAPBB]]
|
||||
// CHECK-DCAST-NEXT: call void @llvm.trap()
|
||||
|
@ -61,7 +61,7 @@ void abrr(A &&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-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-UCAST: [[TRAPBB]]
|
||||
// CHECK-UCAST-NEXT: call void @llvm.trap()
|
||||
|
@ -75,7 +75,7 @@ void vbp(void *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-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-UCAST: [[TRAPBB]]
|
||||
// CHECK-UCAST-NEXT: call void @llvm.trap()
|
||||
|
@ -89,7 +89,7 @@ void vbr(char &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-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK-UCAST: [[TRAPBB]]
|
||||
// CHECK-UCAST-NEXT: call void @llvm.trap()
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck %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=NDIAG %s
|
||||
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --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=DIAG --check-prefix=DIAG-RECOVER %s
|
||||
|
||||
struct A {
|
||||
A();
|
||||
|
@ -33,14 +35,23 @@ void A::f() {
|
|||
void D::f() {
|
||||
}
|
||||
|
||||
// DIAG: @[[SRC:.*]] = private unnamed_addr constant [{{.*}} x i8] c"{{.*}}test/CodeGenCXX/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 { { [{{.*}} x i8]*, i32, i32 }, { i16, i16, [4 x i8] }*, i8 } { { [{{.*}} x i8]*, i32, i32 } { [{{.*}} x i8]* @[[SRC]], i32 58, i32 3 }, { i16, i16, [4 x i8] }* @[[TYPE]], i8 0 }
|
||||
|
||||
// CHECK: define void @_Z2afP1A
|
||||
void af(A *a) {
|
||||
// CHECK: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"1A")
|
||||
// CHECK-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ]*]]
|
||||
// CHECK: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"1A")
|
||||
// CHECK-NEXT: br i1 [[P]], label %[[CONTBB:[^ ,]*]], label %[[TRAPBB:[^ ,]*]]
|
||||
|
||||
// CHECK: [[TRAPBB]]
|
||||
// CHECK-NEXT: call void @llvm.trap()
|
||||
// CHECK-NEXT: unreachable
|
||||
// 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_bad_type_abort(i8* bitcast ({{.*}} @[[BADTYPESTATIC]] to i8*), i64 [[VTINT]])
|
||||
// DIAG-ABORT-NEXT: unreachable
|
||||
// DIAG-RECOVER-NEXT: call void @__ubsan_handle_cfi_bad_type(i8* bitcast ({{.*}} @[[BADTYPESTATIC]] to i8*), i64 [[VTINT]])
|
||||
// DIAG-RECOVER-NEXT: br label %[[CONTBB]]
|
||||
|
||||
// CHECK: [[CONTBB]]
|
||||
// CHECK: call void %
|
||||
|
|
Loading…
Reference in New Issue