if (SanOpts.has(SanitizerKind::Unreachable)) {
SanitizerScope SanScope(this);
EmitCheck(Builder.getFalse(), "builtin_unreachable",
- EmitCheckSourceLocation(E->getExprLoc()),
- None, CRK_Unrecoverable);
+ EmitCheckSourceLocation(E->getExprLoc()), None,
+ SanitizerKind::Unreachable);
} else
Builder.CreateUnreachable();
EmitCheckSourceLocation(EndLoc),
EmitCheckSourceLocation(RetNNAttr->getLocation()),
};
- EmitCheck(Cond, "nonnull_return", StaticData, None, CRK_Recoverable);
+ EmitCheck(Cond, "nonnull_return", StaticData, None,
+ SanitizerKind::ReturnsNonnullAttribute);
}
}
Ret = Builder.CreateRet(RV);
llvm::ConstantInt::get(CGF.Int32Ty, ArgNo + 1),
};
CGF.EmitCheck(Cond, "nonnull_arg", StaticData, None,
- CodeGenFunction::CRK_Recoverable);
+ SanitizerKind::NonnullAttribute);
}
void CodeGenFunction::EmitCallArgs(CallArgList &Args,
if (Address->getType()->getPointerAddressSpace())
return;
+ SmallVector<SanitizerKind, 3> Kinds;
SanitizerScope SanScope(this);
llvm::Value *Cond = nullptr;
Builder.CreateCondBr(Cond, Rest, Done);
EmitBlock(Rest);
Cond = nullptr;
+ } else {
+ Kinds.push_back(SanitizerKind::Null);
}
}
Builder.CreateICmpUGE(Builder.CreateCall2(F, CastAddr, Min),
llvm::ConstantInt::get(IntPtrTy, Size));
Cond = Cond ? Builder.CreateAnd(Cond, LargeEnough) : LargeEnough;
+ Kinds.push_back(SanitizerKind::ObjectSize);
}
uint64_t AlignVal = 0;
llvm::Value *Aligned =
Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
Cond = Cond ? Builder.CreateAnd(Cond, Aligned) : Aligned;
+ Kinds.push_back(SanitizerKind::Alignment);
}
}
llvm::ConstantInt::get(SizeTy, AlignVal),
llvm::ConstantInt::get(Int8Ty, TCK)
};
- EmitCheck(Cond, "type_mismatch", StaticData, Address, CRK_Recoverable);
+ EmitCheck(Cond, "type_mismatch", StaticData, Address, Kinds);
}
// If possible, check that the vptr indicates that there is a subobject of
llvm::ConstantInt::get(Int8Ty, TCK)
};
llvm::Value *DynamicData[] = { Address, Hash };
- EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash),
- "dynamic_type_cache_miss", StaticData, DynamicData,
- CRK_AlwaysRecoverable);
+ EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash), "dynamic_type_cache_miss",
+ StaticData, DynamicData, SanitizerKind::Vptr);
}
}
};
llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexVal, BoundVal)
: Builder.CreateICmpULE(IndexVal, BoundVal);
- EmitCheck(Check, "out_of_bounds", StaticData, Index, CRK_Recoverable);
+ EmitCheck(Check, "out_of_bounds", StaticData, Index,
+ SanitizerKind::ArrayBounds);
}
CGM.DecorateInstruction(Load, TBAAPath, false/*ConvertTypeToTag*/);
}
- if ((SanOpts.has(SanitizerKind::Bool) && hasBooleanRepresentation(Ty)) ||
- (SanOpts.has(SanitizerKind::Enum) && Ty->getAs<EnumType>())) {
+ bool NeedsBoolCheck =
+ SanOpts.has(SanitizerKind::Bool) && hasBooleanRepresentation(Ty);
+ bool NeedsEnumCheck =
+ SanOpts.has(SanitizerKind::Enum) && Ty->getAs<EnumType>();
+ if (NeedsBoolCheck || NeedsEnumCheck) {
SanitizerScope SanScope(this);
llvm::APInt Min, End;
if (getRangeForType(*this, Ty, Min, End, true)) {
EmitCheckTypeDescriptor(Ty)
};
EmitCheck(Check, "load_invalid_value", StaticArgs, EmitCheckValue(Load),
- CRK_Recoverable);
+ NeedsEnumCheck ? SanitizerKind::Enum : SanitizerKind::Bool);
}
} else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
return llvm::ConstantStruct::getAnon(Data);
}
+namespace {
+/// \brief Specify under what conditions this check can be recovered
+enum class CheckRecoverableKind {
+ /// Always terminate program execution if this check fails
+ Unrecoverable,
+ /// Check supports recovering, allows user to specify which
+ Recoverable,
+ /// Runtime conditionally aborts, always need to support recovery.
+ AlwaysRecoverable
+};
+}
+
+static CheckRecoverableKind getRecoverableKind(SanitizerKind Kind) {
+ switch (Kind) {
+ case SanitizerKind::Vptr:
+ return CheckRecoverableKind::AlwaysRecoverable;
+ case SanitizerKind::Return:
+ case SanitizerKind::Unreachable:
+ return CheckRecoverableKind::Unrecoverable;
+ default:
+ return CheckRecoverableKind::Recoverable;
+ }
+}
+
void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
ArrayRef<llvm::Constant *> StaticArgs,
ArrayRef<llvm::Value *> DynamicArgs,
- CheckRecoverableKind RecoverKind) {
+ ArrayRef<SanitizerKind> Kinds) {
assert(IsSanitizerScope);
+ assert(Kinds.size() > 0);
+ CheckRecoverableKind RecoverKind = getRecoverableKind(Kinds[0]);
+ for (int i = 1, n = Kinds.size(); i < n; ++i)
+ assert(RecoverKind == getRecoverableKind(Kinds[i]) &&
+ "All recoverable kinds in a single check must be same!");
+ for (auto Kind : Kinds)
+ assert(SanOpts.has(Kind));
if (CGM.getCodeGenOpts().SanitizeUndefinedTrapOnError) {
- assert (RecoverKind != CRK_AlwaysRecoverable &&
+ assert (RecoverKind != CheckRecoverableKind::AlwaysRecoverable &&
"Runtime call required for AlwaysRecoverable kind!");
return EmitTrapCheck(Checked);
}
ArgTypes.push_back(IntPtrTy);
}
- bool Recover = RecoverKind == CRK_AlwaysRecoverable ||
- (RecoverKind == CRK_Recoverable &&
+ bool Recover = RecoverKind == CheckRecoverableKind::AlwaysRecoverable ||
+ (RecoverKind == CheckRecoverableKind::Recoverable &&
CGM.getCodeGenOpts().SanitizeRecover);
llvm::FunctionType *FnType =
B.addAttribute(llvm::Attribute::UWTable);
// Checks that have two variants use a suffix to differentiate them
- bool NeedsAbortSuffix = RecoverKind != CRK_Unrecoverable &&
+ bool NeedsAbortSuffix = RecoverKind != CheckRecoverableKind::Unrecoverable &&
!CGM.getCodeGenOpts().SanitizeRecover;
std::string FunctionName = ("__ubsan_handle_" + CheckName +
(NeedsAbortSuffix? "_abort" : "")).str();
EmitCheckSourceLocation(E->getLocStart()),
EmitCheckTypeDescriptor(CalleeType)
};
- EmitCheck(CalleeRTTIMatch,
- "function_type_mismatch",
- StaticData,
- Callee,
- CRK_Recoverable);
+ EmitCheck(CalleeRTTIMatch, "function_type_mismatch", StaticData, Callee,
+ SanitizerKind::Function);
Builder.CreateBr(Cont);
EmitBlock(Cont);
return CGF.EmitCheckedLValue(E, TCK);
}
- void EmitBinOpCheck(Value *Check, const BinOpInfo &Info);
+ void EmitBinOpCheck(Value *Check, const BinOpInfo &Info,
+ ArrayRef<SanitizerKind> Kinds);
Value *EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
return CGF.EmitLoadOfLValue(LV, Loc).getScalarVal();
CGF.EmitCheckTypeDescriptor(DstType)
};
CGF.EmitCheck(Check, "float_cast_overflow", StaticArgs, OrigSrc,
- CodeGenFunction::CRK_Recoverable);
+ SanitizerKind::FloatCastOverflow);
}
/// EmitScalarConversion - Emit a conversion from the specified type to the
/// \brief Emit a sanitization check for the given "binary" operation (which
/// might actually be a unary increment which has been lowered to a binary
/// operation). The check passes if \p Check, which is an \c i1, is \c true.
-void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
+void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info,
+ ArrayRef<SanitizerKind> Kinds) {
assert(CGF.IsSanitizerScope);
StringRef CheckName;
SmallVector<llvm::Constant *, 4> StaticData;
CheckName = "divrem_overflow";
StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty));
} else {
- // Signed arithmetic overflow (+, -, *).
+ // Arithmetic overflow (+, -, *).
switch (Opcode) {
case BO_Add: CheckName = "add_overflow"; break;
case BO_Sub: CheckName = "sub_overflow"; break;
DynamicData.push_back(Info.RHS);
}
- CGF.EmitCheck(Check, CheckName, StaticData, DynamicData,
- CodeGenFunction::CRK_Recoverable);
+ CGF.EmitCheck(Check, CheckName, StaticData, DynamicData, Kinds);
}
//===----------------------------------------------------------------------===//
void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) {
llvm::Value *Cond = nullptr;
+ SmallVector<SanitizerKind, 2> Kinds;
- if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero))
+ if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero)) {
Cond = Builder.CreateICmpNE(Ops.RHS, Zero);
+ Kinds.push_back(SanitizerKind::IntegerDivideByZero);
+ }
if (CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) &&
Ops.Ty->hasSignedIntegerRepresentation()) {
llvm::Value *RHSCmp = Builder.CreateICmpNE(Ops.RHS, NegOne);
llvm::Value *Overflow = Builder.CreateOr(LHSCmp, RHSCmp, "or");
Cond = Cond ? Builder.CreateAnd(Cond, Overflow, "and") : Overflow;
+ Kinds.push_back(SanitizerKind::SignedIntegerOverflow);
}
if (Cond)
- EmitBinOpCheck(Cond, Ops);
+ EmitBinOpCheck(Cond, Ops, Kinds);
}
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
} else if (CGF.SanOpts.has(SanitizerKind::FloatDivideByZero) &&
Ops.Ty->isRealFloatingType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
+ EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops,
+ SanitizerKind::FloatDivideByZero);
}
}
// runtime. Otherwise, this is a -ftrapv check, so just emit a trap.
if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
- EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
+ EmitBinOpCheck(Builder.CreateNot(overflow), Ops,
+ isSigned ? SanitizerKind::SignedIntegerOverflow
+ : SanitizerKind::UnsignedIntegerOverflow);
} else
CGF.EmitTrapCheck(Builder.CreateNot(overflow));
return result;
Valid = P;
}
- EmitBinOpCheck(Valid, Ops);
+ EmitBinOpCheck(Valid, Ops, SanitizerKind::Shift);
}
// OpenCL 6.3j: shift values are effectively % word size of LHS.
if (CGF.getLangOpts().OpenCL)
if (CGF.SanOpts.has(SanitizerKind::Shift) && !CGF.getLangOpts().OpenCL &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
- EmitBinOpCheck(Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS)), Ops);
+ EmitBinOpCheck(
+ Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS)), Ops,
+ SanitizerKind::Shift);
}
// OpenCL 6.3j: shift values are effectively % word size of LHS.
if (SanOpts.has(SanitizerKind::Return)) {
SanitizerScope SanScope(this);
EmitCheck(Builder.getFalse(), "missing_return",
- EmitCheckSourceLocation(FD->getLocation()),
- None, CRK_Unrecoverable);
+ EmitCheckSourceLocation(FD->getLocation()), None,
+ SanitizerKind::Return);
} else if (CGM.getCodeGenOpts().OptimizationLevel == 0)
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap));
Builder.CreateUnreachable();
};
EmitCheck(Builder.CreateICmpSGT(Size, Zero),
"vla_bound_not_positive", StaticArgs, Size,
- CRK_Recoverable);
+ SanitizerKind::VLABound);
}
// Always zexting here would be wrong if it weren't
/// passing to a runtime sanitizer handler.
llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc);
- /// \brief Specify under what conditions this check can be recovered
- enum CheckRecoverableKind {
- /// Always terminate program execution if this check fails
- CRK_Unrecoverable,
- /// Check supports recovering, allows user to specify which
- CRK_Recoverable,
- /// Runtime conditionally aborts, always need to support recovery.
- CRK_AlwaysRecoverable
- };
-
/// \brief Create a basic block that will call a handler function in a
/// sanitizer runtime with the provided arguments, and create a conditional
/// branch to it.
void EmitCheck(llvm::Value *Checked, StringRef CheckName,
ArrayRef<llvm::Constant *> StaticArgs,
ArrayRef<llvm::Value *> DynamicArgs,
- CheckRecoverableKind Recoverable);
+ ArrayRef<SanitizerKind> Kinds);
/// \brief Create a basic block that will call the trap intrinsic, and emit a
/// conditional branch to it, for the -ftrapv checks.