[ubsan] Factor out logic to emit a range check. NFC.

This is a readability improvement, but it will also help prep an
upcoming patch to detect UB loads from bitfields.

llvm-svn: 296374
This commit is contained in:
Vedant Kumar 2017-02-27 19:46:19 +00:00
parent aaf5191364
commit 5a97265351
2 changed files with 50 additions and 29 deletions

View File

@ -1301,6 +1301,46 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
return MDHelper.createRange(Min, End);
}
bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
SourceLocation Loc) {
bool HasBoolCheck = SanOpts.has(SanitizerKind::Bool);
bool HasEnumCheck = SanOpts.has(SanitizerKind::Enum);
if (!HasBoolCheck && !HasEnumCheck)
return false;
bool IsBool = hasBooleanRepresentation(Ty) ||
NSAPI(CGM.getContext()).isObjCBOOLType(Ty);
bool NeedsBoolCheck = HasBoolCheck && IsBool;
bool NeedsEnumCheck = HasEnumCheck && Ty->getAs<EnumType>();
if (!NeedsBoolCheck && !NeedsEnumCheck)
return false;
llvm::APInt Min, End;
if (!getRangeForType(*this, Ty, Min, End, /*StrictEnums=*/true, IsBool))
return true;
SanitizerScope SanScope(this);
llvm::Value *Check;
--End;
if (!Min) {
Check = Builder.CreateICmpULE(
Value, llvm::ConstantInt::get(getLLVMContext(), End));
} else {
llvm::Value *Upper = Builder.CreateICmpSLE(
Value, llvm::ConstantInt::get(getLLVMContext(), End));
llvm::Value *Lower = Builder.CreateICmpSGE(
Value, llvm::ConstantInt::get(getLLVMContext(), Min));
Check = Builder.CreateAnd(Upper, Lower);
}
llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc),
EmitCheckTypeDescriptor(Ty)};
SanitizerMask Kind =
NeedsEnumCheck ? SanitizerKind::Enum : SanitizerKind::Bool;
EmitCheck(std::make_pair(Check, Kind), SanitizerHandler::LoadInvalidValue,
StaticArgs, EmitCheckValue(Value));
return true;
}
llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
QualType Ty,
SourceLocation Loc,
@ -1353,35 +1393,9 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
false /*ConvertTypeToTag*/);
}
bool IsBool = hasBooleanRepresentation(Ty) ||
NSAPI(CGM.getContext()).isObjCBOOLType(Ty);
bool NeedsBoolCheck = SanOpts.has(SanitizerKind::Bool) && IsBool;
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, /*StrictEnums=*/true, IsBool)) {
--End;
llvm::Value *Check;
if (!Min)
Check = Builder.CreateICmpULE(
Load, llvm::ConstantInt::get(getLLVMContext(), End));
else {
llvm::Value *Upper = Builder.CreateICmpSLE(
Load, llvm::ConstantInt::get(getLLVMContext(), End));
llvm::Value *Lower = Builder.CreateICmpSGE(
Load, llvm::ConstantInt::get(getLLVMContext(), Min));
Check = Builder.CreateAnd(Upper, Lower);
}
llvm::Constant *StaticArgs[] = {
EmitCheckSourceLocation(Loc),
EmitCheckTypeDescriptor(Ty)
};
SanitizerMask Kind = NeedsEnumCheck ? SanitizerKind::Enum : SanitizerKind::Bool;
EmitCheck(std::make_pair(Check, Kind), SanitizerHandler::LoadInvalidValue,
StaticArgs, EmitCheckValue(Load));
}
if (EmitScalarRangeCheck(Load, Ty, Loc)) {
// In order to prevent the optimizer from throwing away the check, don't
// attach range metadata to the load.
} else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);

View File

@ -2866,6 +2866,13 @@ public:
/// representation to its value representation.
llvm::Value *EmitFromMemory(llvm::Value *Value, QualType Ty);
/// Check if the scalar \p Value is within the valid range for the given
/// type \p Ty.
///
/// Returns true if a check is needed (even if the range is unknown).
bool EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
SourceLocation Loc);
/// EmitLoadOfScalar - Load a scalar value from an address, taking
/// care to appropriately convert from the memory representation to
/// the LLVM value representation.