Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 92 additions & 13 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "CodeGenModule.h"
#include "CodeGenPGO.h"
#include "ConstantEmitter.h"
#include "SanitizerHandler.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
Expand All @@ -37,13 +38,15 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/MatrixBuilder.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/xxhash.h"
Expand Down Expand Up @@ -85,15 +88,84 @@ enum VariableTypeDescriptorKind : uint16_t {
// Miscellaneous Helper Methods
//===--------------------------------------------------------------------===//

static llvm::StringRef GetUBSanTrapForHandler(SanitizerHandler ID) {
switch (ID) {
#define SANITIZER_CHECK(Enum, Name, Version, Msg) \
case SanitizerHandler::Enum: \
return Msg;
LIST_SANITIZER_CHECKS
#undef SANITIZER_CHECK
std::string CodeGenFunction::BuildSanitizerTrapMessage(
SanitizerHandler Handler, QualType LhsTy, QualType OpType, bool IsLeftShift,
bool IsSigned, std::string ReasonStr, bool IsDivideByZero,
bool IsTruncation) {
switch (Handler) {
case SanitizerHandler::AddOverflow:
return llvm::formatv("{0} integer addition overflow on type '{1}'",
IsSigned ? "Signed" : "Unsigned", LhsTy.getAsString());
case SanitizerHandler::BuiltinUnreachable:
return "_builtin_unreachable(), execution reached an unreachable program "
"point";
case SanitizerHandler::CFICheckFail:
return "Control flow integrity check failed";
case SanitizerHandler::DivremOverflow:
return llvm::formatv("{0} on type '{1}'", ReasonStr, LhsTy.getAsString());
case SanitizerHandler::DynamicTypeCacheMiss:
return "Dynamic type cache miss, member call made on an object whose "
"dynamic type differs from the expected type";
case SanitizerHandler::FloatCastOverflow:
return llvm::formatv("Float cast overflow converting from floating-point "
"type '{0}' to integer type '{1}'",
LhsTy.getAsString(), OpType.getAsString());
case SanitizerHandler::FunctionTypeMismatch:
return llvm::formatv("Call through function pointer of type '{0}' with an "
"incompatible target",
(LhsTy->getPointeeType()).getAsString());
case SanitizerHandler::ImplicitConversion:
return llvm::formatv(
"Implicit {0}conversion from '{1}' to '{2}' caused {3}",
IsTruncation ? (IsSigned ? "signed " : "unsigned ") : "",
LhsTy.getAsString(), OpType.getAsString(),
IsTruncation ? "truncation" : "sign-change");
case SanitizerHandler::InvalidBuiltin:
return "Invalid use of builtin function";
case SanitizerHandler::InvalidObjCCast:
return "Invalid Objective-C cast";
case SanitizerHandler::LoadInvalidValue:
return "Loaded an invalid or uninitialized value for the type";
case SanitizerHandler::MissingReturn:
return "Execution reached the end of a value-returning function without "
"returning a value";
case SanitizerHandler::MulOverflow:
return llvm::formatv("{0} integer multiplication overflow on type '{1}'",
IsSigned ? "Signed" : "Unsigned", LhsTy.getAsString());
case SanitizerHandler::NegateOverflow:
return llvm::formatv("Integer negation overflow on type '{0}'",
LhsTy.getAsString());
case SanitizerHandler::NullabilityArg:
return "Passing null as an argument which is annotated with _Nonnull";
case SanitizerHandler::NullabilityReturn:
return "Returning null from a function with a return type annotated with "
"_Nonnull";
case SanitizerHandler::NonnullArg:
return "Passing null pointer as an argument which is declared to never be "
"null";
case SanitizerHandler::NonnullReturn:
return "Returning null pointer from a function which is declared to never "
"return null";
case SanitizerHandler::OutOfBounds:
return "Array index out of bounds";
case SanitizerHandler::PointerOverflow:
return "Pointer arithmetic overflowed bounds";
case SanitizerHandler::ShiftOutOfBounds:
return llvm::formatv("{0} shift is too large for {1}-bit type '{2}'",
IsLeftShift ? "Left" : "Right",
getContext().getIntWidth(LhsTy), LhsTy.getAsString());
case SanitizerHandler::SubOverflow:
return llvm::formatv("{0} integer subtraction overflow on type '{1}'",
IsSigned ? "Signed" : "Unsigned", LhsTy.getAsString());
case SanitizerHandler::TypeMismatch:
return "Type mismatch in operation";
case SanitizerHandler::AlignmentAssumption:
return "Alignment assumption violated";
case SanitizerHandler::VLABoundNotPositive:
return "Variable length array bound evaluates to non-positive value";
default:
return "";
}
llvm_unreachable("unhandled switch case");
}

/// CreateTempAlloca - This creates a alloca and inserts it into the entry
Expand Down Expand Up @@ -3720,7 +3792,7 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
void CodeGenFunction::EmitCheck(
ArrayRef<std::pair<llvm::Value *, SanitizerKind::SanitizerOrdinal>> Checked,
SanitizerHandler CheckHandler, ArrayRef<llvm::Constant *> StaticArgs,
ArrayRef<llvm::Value *> DynamicArgs) {
ArrayRef<llvm::Value *> DynamicArgs, std::string TrapMessage) {
assert(IsSanitizerScope);
assert(Checked.size() > 0);
assert(CheckHandler >= 0 &&
Expand Down Expand Up @@ -3759,7 +3831,7 @@ void CodeGenFunction::EmitCheck(
}

if (TrapCond)
EmitTrapCheck(TrapCond, CheckHandler, NoMerge);
EmitTrapCheck(TrapCond, CheckHandler, NoMerge, TrapMessage);
if (!FatalCond && !RecoverableCond)
return;

Expand Down Expand Up @@ -4071,7 +4143,7 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) {

void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
SanitizerHandler CheckHandlerID,
bool NoMerge) {
bool NoMerge, std::string TrapMessage) {
llvm::BasicBlock *Cont = createBasicBlock("cont");

// If we're optimizing, collapse all calls to trap down to just one per
Expand All @@ -4082,7 +4154,11 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];

llvm::DILocation *TrapLocation = Builder.getCurrentDebugLocation();
llvm::StringRef TrapMessage = GetUBSanTrapForHandler(CheckHandlerID);
// If no additional context was needed for building the trap message, we build
// it here instead
if (TrapMessage.empty()) {
TrapMessage = BuildSanitizerTrapMessage(CheckHandlerID, {}, {});
}

if (getDebugInfo() && !TrapMessage.empty() &&
CGM.getCodeGenOpts().SanitizeDebugTrapReasons && TrapLocation) {
Expand Down Expand Up @@ -6404,8 +6480,11 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
Builder.CreateICmpEQ(CalleeTypeHash, TypeHash);
llvm::Constant *StaticData[] = {EmitCheckSourceLocation(E->getBeginLoc()),
EmitCheckTypeDescriptor(CalleeType)};
std::string Msg =
BuildSanitizerTrapMessage(SanitizerHandler::FunctionTypeMismatch,
CalleeType, {}, {}, {}, {}, {});
EmitCheck(std::make_pair(CalleeTypeHashMatch, CheckOrdinal), CheckHandler,
StaticData, {CalleePtr});
StaticData, {CalleePtr}, Msg);

Builder.CreateBr(Cont);
EmitBlock(Cont);
Expand Down
53 changes: 42 additions & 11 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFixedPoint.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
Expand Down Expand Up @@ -284,7 +285,7 @@ class ScalarExprEmitter

void EmitBinOpCheck(
ArrayRef<std::pair<Value *, SanitizerKind::SanitizerOrdinal>> Checks,
const BinOpInfo &Info);
const BinOpInfo &Info, std::string TrapMessage = "");

Value *EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
return CGF.EmitLoadOfLValue(LV, Loc).getScalarVal();
Expand Down Expand Up @@ -1058,8 +1059,12 @@ void ScalarExprEmitter::EmitFloatConversionCheck(
llvm::Constant *StaticArgs[] = {CGF.EmitCheckSourceLocation(Loc),
CGF.EmitCheckTypeDescriptor(OrigSrcType),
CGF.EmitCheckTypeDescriptor(DstType)};
std::string Msg =
CGF.BuildSanitizerTrapMessage(SanitizerHandler::FloatCastOverflow,
OrigSrcType, DstType, {}, {}, {}, {});

CGF.EmitCheck(std::make_pair(Check, CheckOrdinal), CheckHandler, StaticArgs,
OrigSrc);
OrigSrc, Msg);
}

// Should be called within CodeGenFunction::SanitizerScope RAII scope.
Expand Down Expand Up @@ -1172,7 +1177,11 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType,
llvm::ConstantInt::get(Builder.getInt8Ty(), Check.first),
llvm::ConstantInt::get(Builder.getInt32Ty(), 0)};

CGF.EmitCheck(Check.second, CheckHandler, StaticArgs, {Src, Dst});
std::string Msg = CGF.BuildSanitizerTrapMessage(
SanitizerHandler::ImplicitConversion, SrcType, DstType, {},
(SrcSigned || DstSigned), {}, {}, true);

CGF.EmitCheck(Check.second, CheckHandler, StaticArgs, {Src, Dst}, Msg);
}

static llvm::Value *EmitIsNegativeTestHelper(Value *V, QualType VType,
Expand Down Expand Up @@ -1327,8 +1336,11 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType,
CGF.EmitCheckTypeDescriptor(DstType),
llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind),
llvm::ConstantInt::get(Builder.getInt32Ty(), 0)};
std::string Msg = CGF.BuildSanitizerTrapMessage(
SanitizerHandler::ImplicitConversion, SrcType, DstType, {},
(SrcSigned || DstSigned), {}, {}, false);
// EmitCheck() will 'and' all the checks together.
CGF.EmitCheck(Checks, CheckHandler, StaticArgs, {Src, Dst});
CGF.EmitCheck(Checks, CheckHandler, StaticArgs, {Src, Dst}, Msg);
}

// Should be called within CodeGenFunction::SanitizerScope RAII scope.
Expand Down Expand Up @@ -1808,7 +1820,7 @@ Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
/// are \c true.
void ScalarExprEmitter::EmitBinOpCheck(
ArrayRef<std::pair<Value *, SanitizerKind::SanitizerOrdinal>> Checks,
const BinOpInfo &Info) {
const BinOpInfo &Info, std::string TrapMessage) {
assert(CGF.IsSanitizerScope);
SanitizerHandler Check;
SmallVector<llvm::Constant *, 4> StaticData;
Expand All @@ -1824,6 +1836,8 @@ void ScalarExprEmitter::EmitBinOpCheck(
Check = SanitizerHandler::NegateOverflow;
StaticData.push_back(CGF.EmitCheckTypeDescriptor(UO->getType()));
DynamicData.push_back(Info.RHS);
TrapMessage = CGF.BuildSanitizerTrapMessage(Check, UO->getType(), {}, false,
true, {}, {}, {});
} else {
if (BinaryOperator::isShiftOp(Opcode)) {
// Shift LHS negative or too large, or RHS out of bounds.
Expand Down Expand Up @@ -1851,7 +1865,7 @@ void ScalarExprEmitter::EmitBinOpCheck(
DynamicData.push_back(Info.RHS);
}

CGF.EmitCheck(Checks, Check, StaticData, DynamicData);
CGF.EmitCheck(Checks, Check, StaticData, DynamicData, TrapMessage);
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -3969,8 +3983,10 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) {
SmallVector<std::pair<llvm::Value *, SanitizerKind::SanitizerOrdinal>, 2>
Checks;
std::string ReasonStr;

if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero)) {
ReasonStr = "Division by zero";
Checks.push_back(std::make_pair(Builder.CreateICmpNE(Ops.RHS, Zero),
SanitizerKind::SO_IntegerDivideByZero));
}
Expand All @@ -3991,10 +4007,18 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
llvm::Value *NotOverflow = Builder.CreateOr(LHSCmp, RHSCmp, "or");
Checks.push_back(
std::make_pair(NotOverflow, SanitizerKind::SO_SignedIntegerOverflow));
if (!ReasonStr.empty()) {
ReasonStr += " or signed integer division overflow";
} else {
ReasonStr = "Signed integer division overflow";
}
}

if (Checks.size() > 0)
EmitBinOpCheck(Checks, Ops);
if (Checks.size() > 0) {
std::string Msg = CGF.BuildSanitizerTrapMessage(
SanitizerHandler::DivremOverflow, Ops.Ty, {}, {}, {}, ReasonStr, {});
EmitBinOpCheck(Checks, Ops, Msg);
}
}

Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
Expand Down Expand Up @@ -4132,7 +4156,9 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
SanitizerKind::SanitizerOrdinal Ordinal =
isSigned ? SanitizerKind::SO_SignedIntegerOverflow
: SanitizerKind::SO_UnsignedIntegerOverflow;
EmitBinOpCheck(std::make_pair(NotOverflow, Ordinal), Ops);
std::string Msg = CGF.BuildSanitizerTrapMessage(OverflowKind, Ops.Ty, {},
{}, isSigned, {}, {});
EmitBinOpCheck(std::make_pair(NotOverflow, Ordinal), Ops, Msg);
} else
CGF.EmitTrapCheck(Builder.CreateNot(overflow), OverflowKind);
return result;
Expand Down Expand Up @@ -4774,6 +4800,8 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
RHS = ConstrainShiftValue(Ops.LHS, RHS, "shl.mask");
else if ((SanitizeBase || SanitizeExponent) &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
std::string Msg = CGF.BuildSanitizerTrapMessage(
SanitizerHandler::ShiftOutOfBounds, Ops.Ty, {}, true, {}, {}, {});
SmallVector<SanitizerKind::SanitizerOrdinal, 3> Ordinals;
if (SanitizeSignedBase)
Ordinals.push_back(SanitizerKind::SO_ShiftBase);
Expand Down Expand Up @@ -4832,7 +4860,7 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
}

assert(!Checks.empty());
EmitBinOpCheck(Checks, Ops);
EmitBinOpCheck(Checks, Ops, Msg);
}

return Builder.CreateShl(Ops.LHS, RHS, "shl");
Expand All @@ -4859,7 +4887,10 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
bool RHSIsSigned = Ops.rhsHasSignedIntegerRepresentation();
llvm::Value *Valid = Builder.CreateICmpULE(
Ops.RHS, GetMaximumShiftAmount(Ops.LHS, Ops.RHS, RHSIsSigned));
EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::SO_ShiftExponent), Ops);
std::string Msg = CGF.BuildSanitizerTrapMessage(
SanitizerHandler::ShiftOutOfBounds, Ops.Ty, {}, false, {}, {}, {});
EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::SO_ShiftExponent), Ops,
Msg);
}

if (Ops.Ty->hasUnsignedIntegerRepresentation())
Expand Down
14 changes: 12 additions & 2 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
#include <optional>
#include <string>

namespace llvm {
class BasicBlock;
Expand Down Expand Up @@ -636,6 +638,14 @@ class CodeGenFunction : public CodeGenTypeCache {
/// condition is a known constant.
bool checkIfLoopMustProgress(const Expr *, bool HasEmptyBody);

std::string BuildSanitizerTrapMessage(SanitizerHandler Handler,
QualType LhsTy, QualType OpType,
bool IsLeftShift = false,
bool isSigned = false,
std::string ReasonStr = "",
bool IsDivideByZero = false,
bool IsTruncation = false);

const CodeGen::CGBlockInfo *BlockInfo = nullptr;
llvm::Value *BlockPointer = nullptr;

Expand Down Expand Up @@ -5273,7 +5283,7 @@ class CodeGenFunction : public CodeGenTypeCache {
EmitCheck(ArrayRef<std::pair<llvm::Value *, SanitizerKind::SanitizerOrdinal>>
Checked,
SanitizerHandler Check, ArrayRef<llvm::Constant *> StaticArgs,
ArrayRef<llvm::Value *> DynamicArgs);
ArrayRef<llvm::Value *> DynamicArgs, std::string TrapMessage = "");

/// Emit a slow path cross-DSO CFI check which calls __cfi_slowpath
/// if Cond if false.
Expand All @@ -5289,7 +5299,7 @@ class CodeGenFunction : public CodeGenTypeCache {
/// Create a basic block that will call the trap intrinsic, and emit a
/// conditional branch to it, for the -ftrapv checks.
void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID,
bool NoMerge = false);
bool NoMerge = false, std::string TrapMesage = "");

/// Emit a call to trap or debugtrap and attach function attribute
/// "trap-func-name" if specified.
Expand Down
Loading
Loading