[ubsan] Add more -fsanitize-annotate-debug-info checks (#141997)

This extends https://github.com/llvm/llvm-project/pull/138577 to more UBSan checks, by changing SanitizerDebugLocation (formerly SanitizerScope) to add annotations if enabled for the specified ordinals.

Annotations will use the ordinal name if there is exactly one ordinal specified in the SanitizerDebugLocation; otherwise, it will use the handler name.

Updates the tests from https://github.com/llvm/llvm-project/pull/141814.

---------

Co-authored-by: Vitaly Buka <vitalybuka@google.com>
This commit is contained in:
Thurston Dang 2025-06-06 14:59:32 -07:00 committed by GitHub
parent a42bb8b57a
commit 428afa62b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 407 additions and 252 deletions

View File

@ -2009,11 +2009,12 @@ Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E,
if (!SanOpts.has(SanitizerKind::Builtin))
return ArgValue;
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_Builtin;
auto CheckHandler = SanitizerHandler::InvalidBuiltin;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
Value *Cond = Builder.CreateICmpNE(
ArgValue, llvm::Constant::getNullValue(ArgValue->getType()));
EmitCheck(std::make_pair(Cond, SanitizerKind::SO_Builtin),
SanitizerHandler::InvalidBuiltin,
EmitCheck(std::make_pair(Cond, CheckOrdinal), CheckHandler,
{EmitCheckSourceLocation(E->getExprLoc()),
llvm::ConstantInt::get(Builder.getInt8Ty(), Kind)},
{});
@ -2025,10 +2026,11 @@ Value *CodeGenFunction::EmitCheckedArgForAssume(const Expr *E) {
if (!SanOpts.has(SanitizerKind::Builtin))
return ArgValue;
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_Builtin;
auto CheckHandler = SanitizerHandler::InvalidBuiltin;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
EmitCheck(
std::make_pair(ArgValue, SanitizerKind::SO_Builtin),
SanitizerHandler::InvalidBuiltin,
std::make_pair(ArgValue, CheckOrdinal), CheckHandler,
{EmitCheckSourceLocation(E->getExprLoc()),
llvm::ConstantInt::get(Builder.getInt8Ty(), BCK_AssumePassedFalse)},
std::nullopt);
@ -2051,7 +2053,15 @@ static Value *EmitOverflowCheckedAbs(CodeGenFunction &CGF, const CallExpr *E,
return EmitAbs(CGF, ArgValue, true);
}
CodeGenFunction::SanitizerScope SanScope(&CGF);
SmallVector<SanitizerKind::SanitizerOrdinal, 1> Ordinals;
SanitizerHandler CheckHandler;
if (SanitizeOverflow) {
Ordinals.push_back(SanitizerKind::SO_SignedIntegerOverflow);
CheckHandler = SanitizerHandler::NegateOverflow;
} else
CheckHandler = SanitizerHandler::SubOverflow;
SanitizerDebugLocation SanScope(&CGF, Ordinals, CheckHandler);
Constant *Zero = Constant::getNullValue(ArgValue->getType());
Value *ResultAndOverflow = CGF.Builder.CreateBinaryIntrinsic(
@ -2063,12 +2073,12 @@ static Value *EmitOverflowCheckedAbs(CodeGenFunction &CGF, const CallExpr *E,
// TODO: support -ftrapv-handler.
if (SanitizeOverflow) {
CGF.EmitCheck({{NotOverflow, SanitizerKind::SO_SignedIntegerOverflow}},
SanitizerHandler::NegateOverflow,
CheckHandler,
{CGF.EmitCheckSourceLocation(E->getArg(0)->getExprLoc()),
CGF.EmitCheckTypeDescriptor(E->getType())},
{ArgValue});
} else
CGF.EmitTrapCheck(NotOverflow, SanitizerHandler::SubOverflow);
CGF.EmitTrapCheck(NotOverflow, CheckHandler);
Value *CmpResult = CGF.Builder.CreateICmpSLT(ArgValue, Zero, "abscond");
return CGF.Builder.CreateSelect(CmpResult, Result, ArgValue, "abs");

View File

@ -4184,7 +4184,7 @@ void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV) {
Handler = SanitizerHandler::NullabilityReturn;
}
SanitizerScope SanScope(this);
SanitizerDebugLocation SanScope(this, {CheckKind}, Handler);
// Make sure the "return" source location is valid. If we're checking a
// nullability annotation, make sure the preconditions for the check are met.
@ -4569,7 +4569,7 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
Handler = SanitizerHandler::NullabilityArg;
}
SanitizerScope SanScope(this);
SanitizerDebugLocation SanScope(this, {CheckKind}, Handler);
llvm::Value *Cond = EmitNonNullRValueCheck(RV, ArgType);
llvm::Constant *StaticData[] = {
EmitCheckSourceLocation(ArgLoc),

View File

@ -2817,7 +2817,8 @@ void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD,
RD = LeastDerivedClassWithSameLayout(RD);
auto [Ordinal, _] = SanitizerInfoFromCFICheckKind(TCK);
ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal));
SanitizerDebugLocation SanScope(this, {Ordinal},
SanitizerHandler::CFICheckFail);
EmitVTablePtrCheck(RD, VTable, TCK, Loc);
}
@ -2842,7 +2843,8 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T, Address Derived,
ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
auto [Ordinal, _] = SanitizerInfoFromCFICheckKind(TCK);
ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal));
SanitizerDebugLocation SanScope(this, {Ordinal},
SanitizerHandler::CFICheckFail);
llvm::BasicBlock *ContBlock = nullptr;
@ -2874,6 +2876,8 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
llvm::Value *VTable,
CFITypeCheckKind TCK,
SourceLocation Loc) {
assert(IsSanitizerScope);
if (!CGM.getCodeGenOpts().SanitizeCfiCrossDso &&
!CGM.HasHiddenLTOVisibility(RD))
return;
@ -2885,7 +2889,6 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
SanitizerMask::bitPosToMask(M), TypeName))
return;
SanitizerScope SanScope(this);
EmitSanitizerStatReport(SSK);
llvm::Metadata *MD =
@ -2942,11 +2945,11 @@ bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) {
llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
const CXXRecordDecl *RD, llvm::Value *VTable, llvm::Type *VTableTy,
uint64_t VTableByteOffset) {
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_CFIVCall;
auto CheckHandler = SanitizerHandler::CFICheckFail;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
EmitSanitizerStatReport(llvm::SanStat_CFI_VCall);
ApplyDebugLocation ApplyTrapDI(
*this, SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIVCall));
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
@ -2965,8 +2968,7 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
if (SanOpts.has(SanitizerKind::CFIVCall) &&
!getContext().getNoSanitizeList().containsType(SanitizerKind::CFIVCall,
TypeName)) {
EmitCheck(std::make_pair(CheckResult, SanitizerKind::SO_CFIVCall),
SanitizerHandler::CFICheckFail, {}, {});
EmitCheck(std::make_pair(CheckResult, CheckOrdinal), CheckHandler, {}, {});
}
return Builder.CreateBitCast(Builder.CreateExtractValue(CheckedLoad, 0),

View File

@ -58,6 +58,13 @@
using namespace clang;
using namespace clang::CodeGen;
// TODO: consider deprecating ClArrayBoundsPseudoFn; functionality is subsumed
// by -fsanitize-annotate-debug-info
static llvm::cl::opt<bool> ClArrayBoundsPseudoFn(
"array-bounds-pseudofn", llvm::cl::Hidden, llvm::cl::Optional,
llvm::cl::desc("Emit debug info that places array-bounds instrumentation "
"in an inline function called __ubsan_check_array_bounds."));
static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) {
auto TI = Ctx.getTypeInfo(Ty);
if (TI.isAlignRequired())
@ -6412,3 +6419,78 @@ CodeGenFunction::LexicalScope::~LexicalScope() {
ForceCleanup();
}
}
static std::string SanitizerHandlerToCheckLabel(SanitizerHandler Handler) {
std::string Label;
switch (Handler) {
#define SANITIZER_CHECK(Enum, Name, Version) \
case Enum: \
Label = "__ubsan_check_" #Name; \
break;
LIST_SANITIZER_CHECKS
#undef SANITIZER_CHECK
};
// Label doesn't require sanitization
return Label;
}
static std::string
SanitizerOrdinalToCheckLabel(SanitizerKind::SanitizerOrdinal Ordinal) {
std::string Label;
switch (Ordinal) {
#define SANITIZER(NAME, ID) \
case SanitizerKind::SO_##ID: \
Label = "__ubsan_check_" NAME; \
break;
#include "clang/Basic/Sanitizers.def"
default:
llvm_unreachable("unexpected sanitizer kind");
}
// Sanitize label (convert hyphens to underscores; also futureproof against
// non-alpha)
for (unsigned int i = 0; i < Label.length(); i++)
if (!std::isalpha(Label[i]))
Label[i] = '_';
return Label;
}
llvm::DILocation *CodeGenFunction::SanitizerAnnotateDebugInfo(
ArrayRef<SanitizerKind::SanitizerOrdinal> Ordinals,
SanitizerHandler Handler) {
std::string Label;
if (Ordinals.size() == 1)
Label = SanitizerOrdinalToCheckLabel(Ordinals[0]);
else
Label = SanitizerHandlerToCheckLabel(Handler);
llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
for (auto Ord : Ordinals) {
// TODO: deprecate ClArrayBoundsPseudoFn
if (((ClArrayBoundsPseudoFn && Ord == SanitizerKind::SO_ArrayBounds) ||
CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo.has(Ord)) &&
CheckDI) {
return getDebugInfo()->CreateSyntheticInlineAt(CheckDI, Label);
}
}
return CheckDI;
}
SanitizerDebugLocation::SanitizerDebugLocation(
CodeGenFunction *CGF, ArrayRef<SanitizerKind::SanitizerOrdinal> Ordinals,
SanitizerHandler Handler)
: CGF(CGF),
Apply(*CGF, CGF->SanitizerAnnotateDebugInfo(Ordinals, Handler)) {
assert(!CGF->IsSanitizerScope);
CGF->IsSanitizerScope = true;
}
SanitizerDebugLocation::~SanitizerDebugLocation() {
assert(CGF->IsSanitizerScope);
CGF->IsSanitizerScope = false;
}

View File

@ -14,6 +14,7 @@
#define LLVM_CLANG_LIB_CODEGEN_CGDEBUGINFO_H
#include "CGBuilder.h"
#include "SanitizerHandler.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExternalASTSource.h"
@ -974,6 +975,17 @@ public:
~ApplyInlineDebugLocation();
};
class SanitizerDebugLocation {
CodeGenFunction *CGF;
ApplyDebugLocation Apply;
public:
SanitizerDebugLocation(CodeGenFunction *CGF,
ArrayRef<SanitizerKind::SanitizerOrdinal> Ordinals,
SanitizerHandler Handler);
~SanitizerDebugLocation();
};
} // namespace CodeGen
} // namespace clang

View File

@ -766,14 +766,15 @@ void CodeGenFunction::EmitNullabilityCheck(LValue LHS, llvm::Value *RHS,
// Check if the right hand side of the assignment is nonnull, if the left
// hand side must be nonnull.
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_NullabilityAssign;
auto CheckHandler = SanitizerHandler::TypeMismatch;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
llvm::Value *IsNotNull = Builder.CreateIsNotNull(RHS);
llvm::Constant *StaticData[] = {
EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(LHS.getType()),
llvm::ConstantInt::get(Int8Ty, 0), // The LogAlignment info is unused.
llvm::ConstantInt::get(Int8Ty, TCK_NonnullAssign)};
EmitCheck({{IsNotNull, SanitizerKind::SO_NullabilityAssign}},
SanitizerHandler::TypeMismatch, StaticData, RHS);
EmitCheck({{IsNotNull, CheckOrdinal}}, CheckHandler, StaticData, RHS);
}
void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,

View File

@ -65,13 +65,6 @@ llvm::cl::opt<bool> ClSanitizeGuardChecks(
} // namespace clang
// TODO: consider deprecating ClArrayBoundsPseudoFn; functionality is subsumed
// by -fsanitize-annotate-debug-info
static llvm::cl::opt<bool> ClArrayBoundsPseudoFn(
"array-bounds-pseudofn", llvm::cl::Hidden, llvm::cl::Optional,
llvm::cl::desc("Emit debug info that places array-bounds instrumentation "
"in an inline function called __ubsan_check_array_bounds."));
//===--------------------------------------------------------------------===//
// Defines for metadata
//===--------------------------------------------------------------------===//
@ -751,104 +744,116 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
if (Ty.isVolatileQualified())
return;
SanitizerScope SanScope(this);
SmallVector<std::pair<llvm::Value *, SanitizerKind::SanitizerOrdinal>, 3>
Checks;
llvm::BasicBlock *Done = nullptr;
// Quickly determine whether we have a pointer to an alloca. It's possible
// to skip null checks, and some alignment checks, for these pointers. This
// can reduce compile-time significantly.
auto PtrToAlloca = dyn_cast<llvm::AllocaInst>(Ptr->stripPointerCasts());
llvm::Value *True = llvm::ConstantInt::getTrue(getLLVMContext());
llvm::Value *IsNonNull = nullptr;
bool IsGuaranteedNonNull =
SkippedChecks.has(SanitizerKind::Null) || PtrToAlloca;
bool AllowNullPointers = isNullPointerAllowed(TCK);
if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) &&
!IsGuaranteedNonNull) {
// The glvalue must not be an empty glvalue.
IsNonNull = Builder.CreateIsNotNull(Ptr);
// The IR builder can constant-fold the null check if the pointer points to
// a constant.
IsGuaranteedNonNull = IsNonNull == True;
llvm::BasicBlock *Done = nullptr;
bool DoneViaNullSanitize = false;
// Skip the null check if the pointer is known to be non-null.
if (!IsGuaranteedNonNull) {
if (AllowNullPointers) {
// When performing pointer casts, it's OK if the value is null.
// Skip the remaining checks in that case.
Done = createBasicBlock("null");
llvm::BasicBlock *Rest = createBasicBlock("not.null");
Builder.CreateCondBr(IsNonNull, Rest, Done);
EmitBlock(Rest);
} else {
Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::SO_Null));
{
auto CheckHandler = SanitizerHandler::TypeMismatch;
SanitizerDebugLocation SanScope(this,
{SanitizerKind::SO_Null,
SanitizerKind::SO_ObjectSize,
SanitizerKind::SO_Alignment},
CheckHandler);
SmallVector<std::pair<llvm::Value *, SanitizerKind::SanitizerOrdinal>, 3>
Checks;
llvm::Value *True = llvm::ConstantInt::getTrue(getLLVMContext());
bool AllowNullPointers = isNullPointerAllowed(TCK);
if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) &&
!IsGuaranteedNonNull) {
// The glvalue must not be an empty glvalue.
IsNonNull = Builder.CreateIsNotNull(Ptr);
// The IR builder can constant-fold the null check if the pointer points
// to a constant.
IsGuaranteedNonNull = IsNonNull == True;
// Skip the null check if the pointer is known to be non-null.
if (!IsGuaranteedNonNull) {
if (AllowNullPointers) {
// When performing pointer casts, it's OK if the value is null.
// Skip the remaining checks in that case.
Done = createBasicBlock("null");
DoneViaNullSanitize = true;
llvm::BasicBlock *Rest = createBasicBlock("not.null");
Builder.CreateCondBr(IsNonNull, Rest, Done);
EmitBlock(Rest);
} else {
Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::SO_Null));
}
}
}
}
if (SanOpts.has(SanitizerKind::ObjectSize) &&
!SkippedChecks.has(SanitizerKind::ObjectSize) &&
!Ty->isIncompleteType()) {
uint64_t TySize = CGM.getMinimumObjectSize(Ty).getQuantity();
llvm::Value *Size = llvm::ConstantInt::get(IntPtrTy, TySize);
if (ArraySize)
Size = Builder.CreateMul(Size, ArraySize);
if (SanOpts.has(SanitizerKind::ObjectSize) &&
!SkippedChecks.has(SanitizerKind::ObjectSize) &&
!Ty->isIncompleteType()) {
uint64_t TySize = CGM.getMinimumObjectSize(Ty).getQuantity();
llvm::Value *Size = llvm::ConstantInt::get(IntPtrTy, TySize);
if (ArraySize)
Size = Builder.CreateMul(Size, ArraySize);
// Degenerate case: new X[0] does not need an objectsize check.
llvm::Constant *ConstantSize = dyn_cast<llvm::Constant>(Size);
if (!ConstantSize || !ConstantSize->isNullValue()) {
// The glvalue must refer to a large enough storage region.
// FIXME: If Address Sanitizer is enabled, insert dynamic instrumentation
// to check this.
// FIXME: Get object address space
llvm::Type *Tys[2] = { IntPtrTy, Int8PtrTy };
llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, Tys);
llvm::Value *Min = Builder.getFalse();
llvm::Value *NullIsUnknown = Builder.getFalse();
llvm::Value *Dynamic = Builder.getFalse();
llvm::Value *LargeEnough = Builder.CreateICmpUGE(
Builder.CreateCall(F, {Ptr, Min, NullIsUnknown, Dynamic}), Size);
Checks.push_back(
std::make_pair(LargeEnough, SanitizerKind::SO_ObjectSize));
// Degenerate case: new X[0] does not need an objectsize check.
llvm::Constant *ConstantSize = dyn_cast<llvm::Constant>(Size);
if (!ConstantSize || !ConstantSize->isNullValue()) {
// The glvalue must refer to a large enough storage region.
// FIXME: If Address Sanitizer is enabled, insert dynamic
// instrumentation
// to check this.
// FIXME: Get object address space
llvm::Type *Tys[2] = {IntPtrTy, Int8PtrTy};
llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, Tys);
llvm::Value *Min = Builder.getFalse();
llvm::Value *NullIsUnknown = Builder.getFalse();
llvm::Value *Dynamic = Builder.getFalse();
llvm::Value *LargeEnough = Builder.CreateICmpUGE(
Builder.CreateCall(F, {Ptr, Min, NullIsUnknown, Dynamic}), Size);
Checks.push_back(
std::make_pair(LargeEnough, SanitizerKind::SO_ObjectSize));
}
}
}
llvm::MaybeAlign AlignVal;
llvm::Value *PtrAsInt = nullptr;
llvm::MaybeAlign AlignVal;
llvm::Value *PtrAsInt = nullptr;
if (SanOpts.has(SanitizerKind::Alignment) &&
!SkippedChecks.has(SanitizerKind::Alignment)) {
AlignVal = Alignment.getAsMaybeAlign();
if (!Ty->isIncompleteType() && !AlignVal)
AlignVal = CGM.getNaturalTypeAlignment(Ty, nullptr, nullptr,
/*ForPointeeType=*/true)
.getAsMaybeAlign();
if (SanOpts.has(SanitizerKind::Alignment) &&
!SkippedChecks.has(SanitizerKind::Alignment)) {
AlignVal = Alignment.getAsMaybeAlign();
if (!Ty->isIncompleteType() && !AlignVal)
AlignVal = CGM.getNaturalTypeAlignment(Ty, nullptr, nullptr,
/*ForPointeeType=*/true)
.getAsMaybeAlign();
// The glvalue must be suitably aligned.
if (AlignVal && *AlignVal > llvm::Align(1) &&
(!PtrToAlloca || PtrToAlloca->getAlign() < *AlignVal)) {
PtrAsInt = Builder.CreatePtrToInt(Ptr, IntPtrTy);
llvm::Value *Align = Builder.CreateAnd(
PtrAsInt, llvm::ConstantInt::get(IntPtrTy, AlignVal->value() - 1));
llvm::Value *Aligned =
Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
if (Aligned != True)
Checks.push_back(std::make_pair(Aligned, SanitizerKind::SO_Alignment));
// The glvalue must be suitably aligned.
if (AlignVal && *AlignVal > llvm::Align(1) &&
(!PtrToAlloca || PtrToAlloca->getAlign() < *AlignVal)) {
PtrAsInt = Builder.CreatePtrToInt(Ptr, IntPtrTy);
llvm::Value *Align = Builder.CreateAnd(
PtrAsInt, llvm::ConstantInt::get(IntPtrTy, AlignVal->value() - 1));
llvm::Value *Aligned =
Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
if (Aligned != True)
Checks.push_back(
std::make_pair(Aligned, SanitizerKind::SO_Alignment));
}
}
}
if (Checks.size() > 0) {
llvm::Constant *StaticData[] = {
EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty),
llvm::ConstantInt::get(Int8Ty, AlignVal ? llvm::Log2(*AlignVal) : 1),
llvm::ConstantInt::get(Int8Ty, TCK)};
EmitCheck(Checks, SanitizerHandler::TypeMismatch, StaticData,
PtrAsInt ? PtrAsInt : Ptr);
if (Checks.size() > 0) {
llvm::Constant *StaticData[] = {
EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty),
llvm::ConstantInt::get(Int8Ty, AlignVal ? llvm::Log2(*AlignVal) : 1),
llvm::ConstantInt::get(Int8Ty, TCK)};
EmitCheck(Checks, CheckHandler, StaticData, PtrAsInt ? PtrAsInt : Ptr);
}
}
// If possible, check that the vptr indicates that there is a subobject of
@ -861,6 +866,9 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
// or call a non-static member function
if (SanOpts.has(SanitizerKind::Vptr) &&
!SkippedChecks.has(SanitizerKind::Vptr) && isVptrCheckRequired(TCK, Ty)) {
SanitizerDebugLocation SanScope(this, {SanitizerKind::SO_Vptr},
SanitizerHandler::DynamicTypeCacheMiss);
// Ensure that the pointer is non-null before loading it. If there is no
// compile-time guarantee, reuse the run-time null check or emit a new one.
if (!IsGuaranteedNonNull) {
@ -929,6 +937,11 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
}
if (Done) {
SanitizerDebugLocation SanScope(
this,
{DoneViaNullSanitize ? SanitizerKind::SO_Null : SanitizerKind::SO_Vptr},
DoneViaNullSanitize ? SanitizerHandler::TypeMismatch
: SanitizerHandler::DynamicTypeCacheMiss);
Builder.CreateBr(Done);
EmitBlock(Done);
}
@ -1227,10 +1240,9 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
if (!Bound)
return;
SanitizerScope SanScope(this);
auto CheckKind = SanitizerKind::SO_ArrayBounds;
ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(CheckKind));
auto CheckHandler = SanitizerHandler::OutOfBounds;
SanitizerDebugLocation SanScope(this, {CheckKind}, CheckHandler);
bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
@ -1243,37 +1255,7 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
};
llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexVal, BoundVal)
: Builder.CreateICmpULE(IndexVal, BoundVal);
EmitCheck(std::make_pair(Check, CheckKind), SanitizerHandler::OutOfBounds,
StaticData, Index);
}
llvm::DILocation *CodeGenFunction::SanitizerAnnotateDebugInfo(
SanitizerKind::SanitizerOrdinal CheckKindOrdinal) {
std::string Label;
switch (CheckKindOrdinal) {
#define SANITIZER(NAME, ID) \
case SanitizerKind::SO_##ID: \
Label = "__ubsan_check_" NAME; \
break;
#include "clang/Basic/Sanitizers.def"
default:
llvm_unreachable("unexpected sanitizer kind");
}
// Sanitize label
for (unsigned int i = 0; i < Label.length(); i++)
if (!std::isalpha(Label[i]))
Label[i] = '_';
llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
// TODO: deprecate ClArrayBoundsPseudoFn
if (((ClArrayBoundsPseudoFn &&
CheckKindOrdinal == SanitizerKind::SO_ArrayBounds) ||
CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo.has(CheckKindOrdinal)) &&
CheckDI)
CheckDI = getDebugInfo()->CreateSyntheticInlineAt(CheckDI, Label);
return CheckDI;
EmitCheck(std::make_pair(Check, CheckKind), CheckHandler, StaticData, Index);
}
CodeGenFunction::ComplexPairTy CodeGenFunction::
@ -1997,8 +1979,12 @@ bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
if (!getRangeForType(*this, Ty, Min, End, /*StrictEnums=*/true, IsBool))
return true;
SanitizerKind::SanitizerOrdinal Kind =
NeedsEnumCheck ? SanitizerKind::SO_Enum : SanitizerKind::SO_Bool;
auto &Ctx = getLLVMContext();
SanitizerScope SanScope(this);
auto CheckHandler = SanitizerHandler::LoadInvalidValue;
SanitizerDebugLocation SanScope(this, {Kind}, CheckHandler);
llvm::Value *Check;
--End;
if (!Min) {
@ -2012,10 +1998,7 @@ bool CodeGenFunction::EmitScalarRangeCheck(llvm::Value *Value, QualType Ty,
}
llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc),
EmitCheckTypeDescriptor(Ty)};
SanitizerKind::SanitizerOrdinal Kind =
NeedsEnumCheck ? SanitizerKind::SO_Enum : SanitizerKind::SO_Bool;
EmitCheck(std::make_pair(Check, Kind), SanitizerHandler::LoadInvalidValue,
StaticArgs, Value);
EmitCheck(std::make_pair(Check, Kind), CheckHandler, StaticArgs, Value);
return true;
}
@ -3938,7 +3921,17 @@ void CodeGenFunction::EmitCfiCheckStub() {
// can be nullptr if the calling module has -fsanitize-trap behavior for this
// check kind; in this case __cfi_check_fail traps as well.
void CodeGenFunction::EmitCfiCheckFail() {
SanitizerScope SanScope(this);
auto CheckHandler = SanitizerHandler::CFICheckFail;
// TODO: the SanitizerKind is not yet determined for this check (and might
// not even be available, if Data == nullptr). However, we still want to
// annotate the instrumentation. We approximate this by using all the CFI
// kinds.
SanitizerDebugLocation SanScope(
this,
{SanitizerKind::SO_CFIVCall, SanitizerKind::SO_CFINVCall,
SanitizerKind::SO_CFIDerivedCast, SanitizerKind::SO_CFIUnrelatedCast,
SanitizerKind::SO_CFIICall},
CheckHandler);
FunctionArgList Args;
ImplicitParamDecl ArgData(getContext(), getContext().VoidPtrTy,
ImplicitParamKind::Other);
@ -4001,8 +3994,6 @@ void CodeGenFunction::EmitCfiCheckFail() {
{Addr, AllVtables}),
IntPtrTy);
// TODO: the instructions above are not annotated with debug info. It is
// inconvenient to do so because we have not determined SanitizerKind yet.
const std::pair<int, SanitizerKind::SanitizerOrdinal> CheckKinds[] = {
{CFITCK_VCall, SanitizerKind::SO_CFIVCall},
{CFITCK_NVCall, SanitizerKind::SO_CFINVCall},
@ -4014,7 +4005,8 @@ void CodeGenFunction::EmitCfiCheckFail() {
int Kind = CheckKindOrdinalPair.first;
SanitizerKind::SanitizerOrdinal Ordinal = CheckKindOrdinalPair.second;
ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal));
// TODO: we could apply SanitizerAnnotateDebugInfo(Ordinal) instead of
// relying on the SanitizerScope with all CFI ordinals
llvm::Value *Cond =
Builder.CreateICmpNE(CheckKind, llvm::ConstantInt::get(Int8Ty, Kind));
@ -4026,7 +4018,7 @@ void CodeGenFunction::EmitCfiCheckFail() {
// Although the compiler allows SanitizeMergeHandlers to be set
// independently of CGM.getLangOpts().Sanitize, Driver/SanitizerArgs.cpp
// requires that SanitizeMergeHandlers is a subset of Sanitize.
EmitTrapCheck(Cond, SanitizerHandler::CFICheckFail, /*NoMerge=*/false);
EmitTrapCheck(Cond, CheckHandler, /*NoMerge=*/false);
}
FinishFunction();
@ -4037,11 +4029,12 @@ void CodeGenFunction::EmitCfiCheckFail() {
void CodeGenFunction::EmitUnreachable(SourceLocation Loc) {
if (SanOpts.has(SanitizerKind::Unreachable)) {
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_Unreachable;
auto CheckHandler = SanitizerHandler::BuiltinUnreachable;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
EmitCheck(std::make_pair(static_cast<llvm::Value *>(Builder.getFalse()),
SanitizerKind::SO_Unreachable),
SanitizerHandler::BuiltinUnreachable,
EmitCheckSourceLocation(Loc), {});
CheckOrdinal),
CheckHandler, EmitCheckSourceLocation(Loc), {});
}
Builder.CreateUnreachable();
}
@ -6303,7 +6296,9 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
!isa<FunctionNoProtoType>(PointeeType)) {
if (llvm::Constant *PrefixSig =
CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM)) {
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_Function;
auto CheckHandler = SanitizerHandler::FunctionTypeMismatch;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
auto *TypeHash = getUBSanFunctionTypeHash(PointeeType);
llvm::Type *PrefixSigType = PrefixSig->getType();
@ -6363,9 +6358,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
Builder.CreateICmpEQ(CalleeTypeHash, TypeHash);
llvm::Constant *StaticData[] = {EmitCheckSourceLocation(E->getBeginLoc()),
EmitCheckTypeDescriptor(CalleeType)};
EmitCheck(std::make_pair(CalleeTypeHashMatch, SanitizerKind::SO_Function),
SanitizerHandler::FunctionTypeMismatch, StaticData,
{CalleePtr});
EmitCheck(std::make_pair(CalleeTypeHashMatch, CheckOrdinal), CheckHandler,
StaticData, {CalleePtr});
Builder.CreateBr(Cont);
EmitBlock(Cont);
@ -6385,10 +6379,10 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
// function pointer is a member of the bit set for the function type.
if (SanOpts.has(SanitizerKind::CFIICall) &&
(!TargetDecl || !isa<FunctionDecl>(TargetDecl)) && !CFIUnchecked) {
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_CFIICall;
auto CheckHandler = SanitizerHandler::CFICheckFail;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
ApplyDebugLocation ApplyTrapDI(
*this, SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIICall));
llvm::Metadata *MD;
if (CGM.getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
@ -6409,12 +6403,11 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
EmitCheckTypeDescriptor(QualType(FnType, 0)),
};
if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && CrossDsoTypeId) {
EmitCfiSlowPathCheck(SanitizerKind::SO_CFIICall, TypeTest, CrossDsoTypeId,
CalleePtr, StaticData);
EmitCfiSlowPathCheck(CheckOrdinal, TypeTest, CrossDsoTypeId, CalleePtr,
StaticData);
} else {
EmitCheck(std::make_pair(TypeTest, SanitizerKind::SO_CFIICall),
SanitizerHandler::CFICheckFail, StaticData,
{CalleePtr, llvm::UndefValue::get(IntPtrTy)});
EmitCheck(std::make_pair(TypeTest, CheckOrdinal), CheckHandler,
StaticData, {CalleePtr, llvm::UndefValue::get(IntPtrTy)});
}
}

View File

@ -999,7 +999,9 @@ void ScalarExprEmitter::EmitFloatConversionCheck(
if (!isa<llvm::IntegerType>(DstTy))
return;
CodeGenFunction::SanitizerScope SanScope(&CGF);
auto CheckOrdinal = SanitizerKind::SO_FloatCastOverflow;
auto CheckHandler = SanitizerHandler::FloatCastOverflow;
SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler);
using llvm::APFloat;
using llvm::APSInt;
@ -1056,8 +1058,8 @@ void ScalarExprEmitter::EmitFloatConversionCheck(
llvm::Constant *StaticArgs[] = {CGF.EmitCheckSourceLocation(Loc),
CGF.EmitCheckTypeDescriptor(OrigSrcType),
CGF.EmitCheckTypeDescriptor(DstType)};
CGF.EmitCheck(std::make_pair(Check, SanitizerKind::SO_FloatCastOverflow),
SanitizerHandler::FloatCastOverflow, StaticArgs, OrigSrc);
CGF.EmitCheck(std::make_pair(Check, CheckOrdinal), CheckHandler, StaticArgs,
OrigSrc);
}
// Should be called within CodeGenFunction::SanitizerScope RAII scope.
@ -1134,18 +1136,31 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType,
(!SrcSigned && DstSigned))
return;
CodeGenFunction::SanitizerScope SanScope(&CGF);
std::pair<ScalarExprEmitter::ImplicitConversionCheckKind,
std::pair<llvm::Value *, SanitizerKind::SanitizerOrdinal>>
Check =
EmitIntegerTruncationCheckHelper(Src, SrcType, Dst, DstType, Builder);
// If the comparison result is 'i1 false', then the truncation was lossy.
Check;
auto CheckHandler = SanitizerHandler::ImplicitConversion;
{
// We don't know the check kind until we call
// EmitIntegerTruncationCheckHelper, but we want to annotate
// EmitIntegerTruncationCheckHelper's instructions too.
SanitizerDebugLocation SanScope(
&CGF,
{SanitizerKind::SO_ImplicitUnsignedIntegerTruncation,
SanitizerKind::SO_ImplicitSignedIntegerTruncation},
CheckHandler);
Check =
EmitIntegerTruncationCheckHelper(Src, SrcType, Dst, DstType, Builder);
// If the comparison result is 'i1 false', then the truncation was lossy.
}
// Do we care about this type of truncation?
if (!CGF.SanOpts.has(Check.second.second))
return;
SanitizerDebugLocation SanScope(&CGF, {Check.second.second}, CheckHandler);
// Does some SSCL ignore this type?
if (CGF.getContext().isTypeIgnoredBySanitizer(
SanitizerMask::bitPosToMask(Check.second.second), DstType))
@ -1157,8 +1172,7 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType,
llvm::ConstantInt::get(Builder.getInt8Ty(), Check.first),
llvm::ConstantInt::get(Builder.getInt32Ty(), 0)};
CGF.EmitCheck(Check.second, SanitizerHandler::ImplicitConversion, StaticArgs,
{Src, Dst});
CGF.EmitCheck(Check.second, CheckHandler, StaticArgs, {Src, Dst});
}
static llvm::Value *EmitIsNegativeTestHelper(Value *V, QualType VType,
@ -1272,7 +1286,13 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType,
return;
// That's it. We can't rule out any more cases with the data we have.
CodeGenFunction::SanitizerScope SanScope(&CGF);
auto CheckHandler = SanitizerHandler::ImplicitConversion;
SanitizerDebugLocation SanScope(
&CGF,
{SanitizerKind::SO_ImplicitIntegerSignChange,
SanitizerKind::SO_ImplicitUnsignedIntegerTruncation,
SanitizerKind::SO_ImplicitSignedIntegerTruncation},
CheckHandler);
std::pair<ScalarExprEmitter::ImplicitConversionCheckKind,
std::pair<llvm::Value *, SanitizerKind::SanitizerOrdinal>>
@ -1308,8 +1328,7 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType,
llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind),
llvm::ConstantInt::get(Builder.getInt32Ty(), 0)};
// EmitCheck() will 'and' all the checks together.
CGF.EmitCheck(Checks, SanitizerHandler::ImplicitConversion, StaticArgs,
{Src, Dst});
CGF.EmitCheck(Checks, CheckHandler, StaticArgs, {Src, Dst});
}
// Should be called within CodeGenFunction::SanitizerScope RAII scope.
@ -1393,7 +1412,9 @@ void CodeGenFunction::EmitBitfieldConversionCheck(Value *Src, QualType SrcType,
bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType();
bool DstSigned = DstType->isSignedIntegerOrEnumerationType();
CodeGenFunction::SanitizerScope SanScope(this);
auto CheckHandler = SanitizerHandler::ImplicitConversion;
SanitizerDebugLocation SanScope(
this, {SanitizerKind::SO_ImplicitBitfieldConversion}, CheckHandler);
std::pair<ScalarExprEmitter::ImplicitConversionCheckKind,
std::pair<llvm::Value *, SanitizerKind::SanitizerOrdinal>>
@ -1439,8 +1460,7 @@ void CodeGenFunction::EmitBitfieldConversionCheck(Value *Src, QualType SrcType,
llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind),
llvm::ConstantInt::get(Builder.getInt32Ty(), Info.Size)};
EmitCheck(Check.second, SanitizerHandler::ImplicitConversion, StaticArgs,
{Src, Dst});
EmitCheck(Check.second, CheckHandler, StaticArgs, {Src, Dst});
}
Value *ScalarExprEmitter::EmitScalarCast(Value *Src, QualType SrcType,
@ -3975,7 +3995,11 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
{
CodeGenFunction::SanitizerScope SanScope(&CGF);
SanitizerDebugLocation SanScope(&CGF,
{SanitizerKind::SO_IntegerDivideByZero,
SanitizerKind::SO_SignedIntegerOverflow,
SanitizerKind::SO_FloatDivideByZero},
SanitizerHandler::DivremOverflow);
if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) ||
CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) &&
Ops.Ty->isIntegerType() &&
@ -4029,7 +4053,10 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) &&
Ops.Ty->isIntegerType() &&
(Ops.mayHaveIntegerDivisionByZero() || Ops.mayHaveIntegerOverflow())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
SanitizerDebugLocation SanScope(&CGF,
{SanitizerKind::SO_IntegerDivideByZero,
SanitizerKind::SO_SignedIntegerOverflow},
SanitizerHandler::DivremOverflow);
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false);
}
@ -4078,7 +4105,10 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
if (isSigned)
OpID |= 1;
CodeGenFunction::SanitizerScope SanScope(&CGF);
SanitizerDebugLocation SanScope(&CGF,
{SanitizerKind::SO_SignedIntegerOverflow,
SanitizerKind::SO_UnsignedIntegerOverflow},
OverflowKind);
llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
llvm::Function *intrinsic = CGF.CGM.getIntrinsic(IID, opTy);
@ -4204,7 +4234,9 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
PtrTy->getPointerAddressSpace()))
return Ptr;
// The inbounds GEP of null is valid iff the index is zero.
CodeGenFunction::SanitizerScope SanScope(&CGF);
auto CheckOrdinal = SanitizerKind::SO_PointerOverflow;
auto CheckHandler = SanitizerHandler::PointerOverflow;
SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler);
Value *IsZeroIndex = CGF.Builder.CreateIsNull(index);
llvm::Constant *StaticArgs[] = {
CGF.EmitCheckSourceLocation(op.E->getExprLoc())};
@ -4212,8 +4244,8 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
Value *IntPtr = llvm::Constant::getNullValue(IntPtrTy);
Value *ComputedGEP = CGF.Builder.CreateZExtOrTrunc(index, IntPtrTy);
Value *DynamicArgs[] = {IntPtr, ComputedGEP};
CGF.EmitCheck({{IsZeroIndex, SanitizerKind::SO_PointerOverflow}},
SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs);
CGF.EmitCheck({{IsZeroIndex, CheckOrdinal}}, CheckHandler, StaticArgs,
DynamicArgs);
return Ptr;
}
@ -4734,7 +4766,16 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
RHS = ConstrainShiftValue(Ops.LHS, RHS, "shl.mask");
else if ((SanitizeBase || SanitizeExponent) &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
SmallVector<SanitizerKind::SanitizerOrdinal, 3> Ordinals;
if (SanitizeSignedBase)
Ordinals.push_back(SanitizerKind::SO_ShiftBase);
if (SanitizeUnsignedBase)
Ordinals.push_back(SanitizerKind::SO_UnsignedShiftBase);
if (SanitizeExponent)
Ordinals.push_back(SanitizerKind::SO_ShiftExponent);
SanitizerDebugLocation SanScope(&CGF, Ordinals,
SanitizerHandler::ShiftOutOfBounds);
SmallVector<std::pair<Value *, SanitizerKind::SanitizerOrdinal>, 2> Checks;
bool RHSIsSigned = Ops.rhsHasSignedIntegerRepresentation();
llvm::Value *WidthMinusOne =
@ -4805,7 +4846,8 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
RHS = ConstrainShiftValue(Ops.LHS, RHS, "shr.mask");
else if (CGF.SanOpts.has(SanitizerKind::ShiftExponent) &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
SanitizerDebugLocation SanScope(&CGF, {SanitizerKind::SO_ShiftExponent},
SanitizerHandler::ShiftOutOfBounds);
bool RHSIsSigned = Ops.rhsHasSignedIntegerRepresentation();
llvm::Value *Valid = Builder.CreateICmpULE(
Ops.RHS, GetMaximumShiftAmount(Ops.LHS, Ops.RHS, RHSIsSigned));
@ -6037,7 +6079,9 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr,
const auto &DL = CGM.getDataLayout();
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_PointerOverflow;
auto CheckHandler = SanitizerHandler::PointerOverflow;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
llvm::Type *IntPtrTy = DL.getIntPtrType(PtrTy);
GEPOffsetAndOverflow EvaluatedGEP =
@ -6074,7 +6118,7 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr,
auto *BaseIsNotNullptr = Builder.CreateIsNotNull(Ptr);
auto *ResultIsNotNullptr = Builder.CreateIsNotNull(ComputedGEP);
auto *Valid = Builder.CreateICmpEQ(BaseIsNotNullptr, ResultIsNotNullptr);
Checks.emplace_back(Valid, SanitizerKind::SO_PointerOverflow);
Checks.emplace_back(Valid, CheckOrdinal);
}
if (PerformOverflowCheck) {
@ -6110,7 +6154,7 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr,
ValidGEP = Builder.CreateICmpULE(ComputedGEP, IntPtr);
}
ValidGEP = Builder.CreateAnd(ValidGEP, NoOffsetOverflow);
Checks.emplace_back(ValidGEP, SanitizerKind::SO_PointerOverflow);
Checks.emplace_back(ValidGEP, CheckOrdinal);
}
assert(!Checks.empty() && "Should have produced some checks.");
@ -6118,7 +6162,7 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr,
llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)};
// Pass the computed GEP to the runtime to avoid emitting poisoned arguments.
llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP};
EmitCheck(Checks, SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs);
EmitCheck(Checks, CheckHandler, StaticArgs, DynamicArgs);
return GEPVal;
}

View File

@ -1968,7 +1968,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
const ObjCInterfaceType *InterfaceTy =
ObjPtrTy ? ObjPtrTy->getInterfaceType() : nullptr;
if (InterfaceTy) {
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_ObjCCast;
auto CheckHandler = SanitizerHandler::InvalidObjCCast;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
auto &C = CGM.getContext();
assert(InterfaceTy->getDecl() && "No decl for ObjC interface type");
Selector IsKindOfClassSel = GetUnarySelector("isKindOfClass", C);
@ -1985,8 +1987,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::Constant *StaticData[] = {
EmitCheckSourceLocation(S.getBeginLoc()),
EmitCheckTypeDescriptor(QualType(InterfaceTy, 0))};
EmitCheck({{IsClass, SanitizerKind::SO_ObjCCast}},
SanitizerHandler::InvalidObjCCast,
EmitCheck({{IsClass, CheckOrdinal}}, CheckHandler,
ArrayRef<llvm::Constant *>(StaticData), CurrentItem);
}
}

View File

@ -1636,10 +1636,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
CGM.getCodeGenOpts().StrictReturn ||
!CGM.MayDropFunctionReturn(FD->getASTContext(), FD->getReturnType());
if (SanOpts.has(SanitizerKind::Return)) {
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_Return;
auto CheckHandler = SanitizerHandler::MissingReturn;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
llvm::Value *IsFalse = Builder.getFalse();
EmitCheck(std::make_pair(IsFalse, SanitizerKind::SO_Return),
SanitizerHandler::MissingReturn,
EmitCheck(std::make_pair(IsFalse, CheckOrdinal), CheckHandler,
EmitCheckSourceLocation(FD->getLocation()), {});
} else if (ShouldEmitUnreachable) {
if (CGM.getCodeGenOpts().OptimizationLevel == 0)
@ -2541,7 +2542,9 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
// expression [...] each time it is evaluated it shall have a value
// greater than zero.
if (SanOpts.has(SanitizerKind::VLABound)) {
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_VLABound;
auto CheckHandler = SanitizerHandler::VLABoundNotPositive;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
llvm::Value *Zero = llvm::Constant::getNullValue(size->getType());
clang::QualType SEType = sizeExpr->getType();
llvm::Value *CheckCondition =
@ -2551,9 +2554,8 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
llvm::Constant *StaticArgs[] = {
EmitCheckSourceLocation(sizeExpr->getBeginLoc()),
EmitCheckTypeDescriptor(SEType)};
EmitCheck(
std::make_pair(CheckCondition, SanitizerKind::SO_VLABound),
SanitizerHandler::VLABoundNotPositive, StaticArgs, size);
EmitCheck(std::make_pair(CheckCondition, CheckOrdinal),
CheckHandler, StaticArgs, size);
}
// Always zexting here would be wrong if it weren't
@ -3196,7 +3198,9 @@ void CodeGenFunction::emitAlignmentAssumptionCheck(
Assumption->removeFromParent();
{
SanitizerScope SanScope(this);
auto CheckOrdinal = SanitizerKind::SO_Alignment;
auto CheckHandler = SanitizerHandler::AlignmentAssumption;
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
if (!OffsetValue)
OffsetValue = Builder.getInt1(false); // no offset.
@ -3205,8 +3209,8 @@ void CodeGenFunction::emitAlignmentAssumptionCheck(
EmitCheckSourceLocation(SecondaryLoc),
EmitCheckTypeDescriptor(Ty)};
llvm::Value *DynamicData[] = {Ptr, Alignment, OffsetValue};
EmitCheck({std::make_pair(TheCheck, SanitizerKind::SO_Alignment)},
SanitizerHandler::AlignmentAssumption, StaticData, DynamicData);
EmitCheck({std::make_pair(TheCheck, CheckOrdinal)}, CheckHandler,
StaticData, DynamicData);
}
// We are now in the (new, empty) "cont" basic block.

View File

@ -3332,10 +3332,12 @@ public:
llvm::Value *Index, QualType IndexType,
QualType IndexedType, bool Accessed);
/// Returns debug info, with additional annotation if enabled by
/// CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo[CheckKindOrdinal].
/// Returns debug info, with additional annotation if
/// CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo[Ordinal] is enabled for
/// any of the ordinals.
llvm::DILocation *
SanitizerAnnotateDebugInfo(SanitizerKind::SanitizerOrdinal CheckKindOrdinal);
SanitizerAnnotateDebugInfo(ArrayRef<SanitizerKind::SanitizerOrdinal> Ordinals,
SanitizerHandler Handler);
llvm::Value *GetCountedByFieldExprGEP(const Expr *Base, const FieldDecl *FD,
const FieldDecl *CountDecl);

View File

@ -713,9 +713,9 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
llvm::Value *VirtualFn = nullptr;
{
CodeGenFunction::SanitizerScope SanScope(&CGF);
ApplyDebugLocation ApplyTrapDI(
CGF, CGF.SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIMFCall));
auto CheckOrdinal = SanitizerKind::SO_CFIMFCall;
auto CheckHandler = SanitizerHandler::CFICheckFail;
SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler);
llvm::Value *TypeId = nullptr;
llvm::Value *CheckResult = nullptr;
@ -785,16 +785,15 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
};
if (CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIMFCall)) {
CGF.EmitTrapCheck(CheckResult, SanitizerHandler::CFICheckFail);
CGF.EmitTrapCheck(CheckResult, CheckHandler);
} else {
llvm::Value *AllVtables = llvm::MetadataAsValue::get(
CGM.getLLVMContext(),
llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
llvm::Value *ValidVtable = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test), {VTable, AllVtables});
CGF.EmitCheck(std::make_pair(CheckResult, SanitizerKind::SO_CFIMFCall),
SanitizerHandler::CFICheckFail, StaticData,
{VTable, ValidVtable});
CGF.EmitCheck(std::make_pair(CheckResult, CheckOrdinal), CheckHandler,
StaticData, {VTable, ValidVtable});
}
FnVirtual = Builder.GetInsertBlock();
@ -813,9 +812,9 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
if (ShouldEmitCFICheck) {
CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
if (RD->hasDefinition()) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
ApplyDebugLocation ApplyTrapDI(
CGF, CGF.SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIMFCall));
auto CheckOrdinal = SanitizerKind::SO_CFIMFCall;
auto CheckHandler = SanitizerHandler::CFICheckFail;
SanitizerDebugLocation SanScope(&CGF, {CheckOrdinal}, CheckHandler);
llvm::Constant *StaticData[] = {
llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_NVMFCall),
@ -838,8 +837,7 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
Bit = Builder.CreateOr(Bit, TypeTest);
}
CGF.EmitCheck(std::make_pair(Bit, SanitizerKind::SO_CFIMFCall),
SanitizerHandler::CFICheckFail, StaticData,
CGF.EmitCheck(std::make_pair(Bit, CheckOrdinal), CheckHandler, StaticData,
{NonVirtualFn, llvm::UndefValue::get(CGF.IntPtrTy)});
FnNonVirtual = Builder.GetInsertBlock();

View File

@ -18,26 +18,26 @@ void call_no_prototype(void (*f)()) { f(); }
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: #dbg_value(ptr [[F]], [[META25:![0-9]+]], !DIExpression(), [[META27:![0-9]+]])
// CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[F]], i64 -8, !dbg [[DBG28:![0-9]+]]
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !dbg [[DBG28]], !nosanitize [[META29:![0-9]+]]
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], -1056584962, !dbg [[DBG28]], !nosanitize [[META29]]
// CHECK-NEXT: br i1 [[TMP2]], label %[[TYPECHECK:.*]], label %[[CONT1:.*]], !dbg [[DBG28]], !nosanitize [[META29]]
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !dbg [[DBG28]], !nosanitize [[META32:![0-9]+]]
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], -1056584962, !dbg [[DBG28]], !nosanitize [[META32]]
// CHECK-NEXT: br i1 [[TMP2]], label %[[TYPECHECK:.*]], label %[[CONT1:.*]], !dbg [[DBG28]], !nosanitize [[META32]]
// CHECK: [[TYPECHECK]]:
// CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[F]], i64 -4, !dbg [[DBG28]]
// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 8, !dbg [[DBG28]], !nosanitize [[META29]]
// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 905068220, !dbg [[DBG28]], !nosanitize [[META29]]
// CHECK-NEXT: br i1 [[TMP5]], label %[[CONT1]], label %[[HANDLER_FUNCTION_TYPE_MISMATCH:.*]], !dbg [[DBG28]], !prof [[PROF30:![0-9]+]], !nosanitize [[META29]]
// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 8, !dbg [[DBG28]], !nosanitize [[META32]]
// CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP4]], 905068220, !dbg [[DBG28]], !nosanitize [[META32]]
// CHECK-NEXT: br i1 [[TMP5]], label %[[CONT1]], label %[[HANDLER_FUNCTION_TYPE_MISMATCH:.*]], !dbg [[DBG28]], !prof [[PROF33:![0-9]+]], !nosanitize [[META32]]
// CHECK: [[HANDLER_FUNCTION_TYPE_MISMATCH]]:
// CHECK-NEXT: [[TMP6:%.*]] = ptrtoint ptr [[F]] to i64, !dbg [[DBG28]], !nosanitize [[META29]]
// CHECK-NEXT: tail call void @__ubsan_handle_function_type_mismatch_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP6]]) #[[ATTR3:[0-9]+]], !dbg [[DBG28]], !nosanitize [[META29]]
// CHECK-NEXT: unreachable, !dbg [[DBG28]], !nosanitize [[META29]]
// CHECK-NEXT: [[TMP6:%.*]] = ptrtoint ptr [[F]] to i64, !dbg [[DBG28]], !nosanitize [[META32]]
// CHECK-NEXT: tail call void @__ubsan_handle_function_type_mismatch_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP6]]) #[[ATTR3:[0-9]+]], !dbg [[DBG28]], !nosanitize [[META32]]
// CHECK-NEXT: unreachable, !dbg [[DBG28]], !nosanitize [[META32]]
// CHECK: [[CONT1]]:
// CHECK-NEXT: tail call void [[F]]() #[[ATTR2]], !dbg [[DBG28]]
// CHECK-NEXT: ret void, !dbg [[DBG31:![0-9]+]]
// CHECK-NEXT: tail call void [[F]]() #[[ATTR2]], !dbg [[DBG31:![0-9]+]]
// CHECK-NEXT: ret void, !dbg [[DBG34:![0-9]+]]
//
void call_prototype(void (*f)(void)) { f(); }
//.
// CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
// CHECK: [[META1]] = !DIFile(filename: "<stdin>", directory: {{.*}})
// CHECK: [[META1]] = !DIFile(filename: "{{.*}}<stdin>", directory: {{.*}})
// CHECK: [[DBG5]] = distinct !DISubprogram(name: "call_no_prototype", scope: [[META6:![0-9]+]], file: [[META6]], line: 14, type: [[META7:![0-9]+]], scopeLine: 14, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META12:![0-9]+]])
// CHECK: [[META6]] = !DIFile(filename: "{{.*}}ubsan-function-debuginfo.c", directory: {{.*}})
// CHECK: [[META7]] = !DISubroutineType(types: [[META8:![0-9]+]])
@ -61,8 +61,11 @@ void call_prototype(void (*f)(void)) { f(); }
// CHECK: [[META25]] = !DILocalVariable(name: "f", arg: 1, scope: [[DBG18]], file: [[META6]], line: 37, type: [[META21]])
// CHECK: [[META26]] = !{i32 -1056584962, i32 -747727454}
// CHECK: [[META27]] = !DILocation(line: 0, scope: [[DBG18]])
// CHECK: [[DBG28]] = !DILocation(line: 37, column: 40, scope: [[DBG18]])
// CHECK: [[META29]] = !{}
// CHECK: [[PROF30]] = !{!"branch_weights", i32 1048575, i32 1}
// CHECK: [[DBG31]] = !DILocation(line: 37, column: 45, scope: [[DBG18]])
// CHECK: [[DBG28]] = !DILocation(line: 0, scope: [[META29:![0-9]+]], inlinedAt: [[DBG31]])
// CHECK: [[META29]] = distinct !DISubprogram(name: "__ubsan_check_function", scope: [[META6]], file: [[META6]], type: [[META30:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
// CHECK: [[META30]] = !DISubroutineType(types: null)
// CHECK: [[DBG31]] = !DILocation(line: 37, column: 40, scope: [[DBG18]])
// CHECK: [[META32]] = !{}
// CHECK: [[PROF33]] = !{!"branch_weights", i32 1048575, i32 1}
// CHECK: [[DBG34]] = !DILocation(line: 37, column: 45, scope: [[DBG18]])
//.

View File

@ -18,19 +18,19 @@ unsigned short si, sj, sk;
// CHECKS-NEXT: [[CONV:%.*]] = zext i16 [[TMP0]] to i32, !dbg [[DBG16]]
// CHECKS-NEXT: [[TMP1:%.*]] = load i16, ptr @sk, align 2, !dbg [[DBG21:![0-9]+]], !tbaa [[TBAA17]]
// CHECKS-NEXT: [[CONV1:%.*]] = zext i16 [[TMP1]] to i32, !dbg [[DBG21]]
// CHECKS-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[CONV]], i32 [[CONV1]]), !dbg [[DBG22:![0-9]+]], !nosanitize [[META23:![0-9]+]]
// CHECKS-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !dbg [[DBG22]], !nosanitize [[META23]]
// CHECKS-NEXT: br i1 [[TMP3]], label %[[HANDLER_MUL_OVERFLOW:.*]], label %[[CONT:.*]], !dbg [[DBG22]], !prof [[PROF24:![0-9]+]], !nosanitize [[META23]]
// CHECKS-NEXT: [[TMP2:%.*]] = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[CONV]], i32 [[CONV1]]), !dbg [[DBG22:![0-9]+]], !nosanitize [[META26:![0-9]+]]
// CHECKS-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP2]], 1, !dbg [[DBG22]], !nosanitize [[META26]]
// CHECKS-NEXT: br i1 [[TMP3]], label %[[HANDLER_MUL_OVERFLOW:.*]], label %[[CONT:.*]], !dbg [[DBG22]], !prof [[PROF27:![0-9]+]], !nosanitize [[META26]]
// CHECKS: [[HANDLER_MUL_OVERFLOW]]:
// CHECKS-NEXT: [[TMP4:%.*]] = zext i16 [[TMP0]] to i64, !dbg [[DBG22]]
// CHECKS-NEXT: [[TMP5:%.*]] = zext i16 [[TMP1]] to i64, !dbg [[DBG22]]
// CHECKS-NEXT: tail call void @__ubsan_handle_mul_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP4]], i64 [[TMP5]]) #[[ATTR3:[0-9]+]], !dbg [[DBG22]], !nosanitize [[META23]]
// CHECKS-NEXT: unreachable, !dbg [[DBG22]], !nosanitize [[META23]]
// CHECKS-NEXT: tail call void @__ubsan_handle_mul_overflow_abort(ptr nonnull @[[GLOB1:[0-9]+]], i64 [[TMP4]], i64 [[TMP5]]) #[[ATTR3:[0-9]+]], !dbg [[DBG22]], !nosanitize [[META26]]
// CHECKS-NEXT: unreachable, !dbg [[DBG22]], !nosanitize [[META26]]
// CHECKS: [[CONT]]:
// CHECKS-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !dbg [[DBG22]], !nosanitize [[META23]]
// CHECKS-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP2]], 0, !dbg [[DBG22]], !nosanitize [[META26]]
// CHECKS-NEXT: [[CONV2:%.*]] = trunc i32 [[TMP6]] to i16, !dbg [[DBG16]]
// CHECKS-NEXT: store i16 [[CONV2]], ptr @si, align 2, !dbg [[DBG25:![0-9]+]], !tbaa [[TBAA17]]
// CHECKS-NEXT: ret void, !dbg [[DBG26:![0-9]+]]
// CHECKS-NEXT: store i16 [[CONV2]], ptr @si, align 2, !dbg [[DBG28:![0-9]+]], !tbaa [[TBAA17]]
// CHECKS-NEXT: ret void, !dbg [[DBG29:![0-9]+]]
//
// CHECKU-LABEL: define dso_local void @testshortmul(
// CHECKU-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] !dbg [[DBG13:![0-9]+]] {
@ -67,11 +67,14 @@ void testshortmul(void) {
// CHECKS: [[META19]] = !{!"omnipotent char", [[META20:![0-9]+]], i64 0}
// CHECKS: [[META20]] = !{!"Simple C/C++ TBAA"}
// CHECKS: [[DBG21]] = !DILocation(line: 47, column: 13, scope: [[DBG13]])
// CHECKS: [[DBG22]] = !DILocation(line: 47, column: 11, scope: [[DBG13]])
// CHECKS: [[META23]] = !{}
// CHECKS: [[PROF24]] = !{!"branch_weights", i32 1, i32 1048575}
// CHECKS: [[DBG25]] = !DILocation(line: 47, column: 6, scope: [[DBG13]])
// CHECKS: [[DBG26]] = !DILocation(line: 48, column: 1, scope: [[DBG13]])
// CHECKS: [[DBG22]] = !DILocation(line: 0, scope: [[META23:![0-9]+]], inlinedAt: [[META25:![0-9]+]])
// CHECKS: [[META23]] = distinct !DISubprogram(name: "__ubsan_check_mul_overflow", scope: [[META7]], file: [[META7]], type: [[META24:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META2]])
// CHECKS: [[META24]] = !DISubroutineType(types: null)
// CHECKS: [[META25]] = !DILocation(line: 47, column: 11, scope: [[DBG13]])
// CHECKS: [[META26]] = !{}
// CHECKS: [[PROF27]] = !{!"branch_weights", i32 1, i32 1048575}
// CHECKS: [[DBG28]] = !DILocation(line: 47, column: 6, scope: [[DBG13]])
// CHECKS: [[DBG29]] = !DILocation(line: 48, column: 1, scope: [[DBG13]])
//.
// CHECKU: [[META0:![0-9]+]] = !DIGlobalVariableExpression(var: [[META1:![0-9]+]], expr: !DIExpression())
// CHECKU: [[META1]] = distinct !DIGlobalVariable(name: "sj", scope: [[META2:![0-9]+]], file: [[META7:![0-9]+]], line: 12, type: [[META8:![0-9]+]], isLocal: false, isDefinition: true)