[Clang][counted_by] Correct signed counted_by values (#171260)

If the 'counted_by' value is signed, we will incorrectly allow accesses
when the value is negative. This has obvious bad effects as it will
allow accessing a huge swath of unallocated memory.

Also clarify and rearrange the parameters to make them more
perspicuous.

Fixes: #170987.
This commit is contained in:
Bill Wendling 2025-12-10 15:18:09 -08:00 committed by GitHub
parent 871dabc8ea
commit 069d3aa923
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 566 additions and 412 deletions

View File

@ -1235,43 +1235,65 @@ llvm::Value *CodeGenFunction::EmitLoadOfCountedByField(
return nullptr;
}
void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
llvm::Value *Index, QualType IndexType,
void CodeGenFunction::EmitBoundsCheck(const Expr *ArrayExpr,
const Expr *ArrayExprBase,
llvm::Value *IndexVal, QualType IndexType,
bool Accessed) {
assert(SanOpts.has(SanitizerKind::ArrayBounds) &&
"should not be called unless adding bounds checks");
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
getLangOpts().getStrictFlexArraysLevel();
QualType IndexedType;
llvm::Value *Bound =
getArrayIndexingBound(*this, Base, IndexedType, StrictFlexArraysLevel);
QualType ArrayExprBaseType;
llvm::Value *BoundsVal = getArrayIndexingBound(
*this, ArrayExprBase, ArrayExprBaseType, StrictFlexArraysLevel);
EmitBoundsCheckImpl(E, Bound, Index, IndexType, IndexedType, Accessed);
EmitBoundsCheckImpl(ArrayExpr, ArrayExprBaseType, IndexVal, IndexType,
BoundsVal, getContext().getSizeType(), Accessed);
}
void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
llvm::Value *Index,
void CodeGenFunction::EmitBoundsCheckImpl(const Expr *ArrayExpr,
QualType ArrayBaseType,
llvm::Value *IndexVal,
QualType IndexType,
QualType IndexedType, bool Accessed) {
if (!Bound)
llvm::Value *BoundsVal,
QualType BoundsType, bool Accessed) {
if (!BoundsVal)
return;
auto CheckKind = SanitizerKind::SO_ArrayBounds;
auto CheckHandler = SanitizerHandler::OutOfBounds;
SanitizerDebugLocation SanScope(this, {CheckKind}, CheckHandler);
// All hail the C implicit type conversion rules!!!
bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
llvm::Value *BoundVal = Builder.CreateIntCast(Bound, SizeTy, false);
bool BoundsSigned = BoundsType->isSignedIntegerOrEnumerationType();
const ASTContext &Ctx = getContext();
llvm::Type *Ty = ConvertType(
Ctx.getTypeSize(IndexType) >= Ctx.getTypeSize(BoundsType) ? IndexType
: BoundsType);
llvm::Value *IndexInst = Builder.CreateIntCast(IndexVal, Ty, IndexSigned);
llvm::Value *BoundsInst = Builder.CreateIntCast(BoundsVal, Ty, false);
llvm::Constant *StaticData[] = {
EmitCheckSourceLocation(E->getExprLoc()),
EmitCheckTypeDescriptor(IndexedType),
EmitCheckTypeDescriptor(IndexType)
EmitCheckSourceLocation(ArrayExpr->getExprLoc()),
EmitCheckTypeDescriptor(ArrayBaseType),
EmitCheckTypeDescriptor(IndexType),
};
llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexVal, BoundVal)
: Builder.CreateICmpULE(IndexVal, BoundVal);
EmitCheck(std::make_pair(Check, CheckKind), CheckHandler, StaticData, Index);
llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexInst, BoundsInst)
: Builder.CreateICmpULE(IndexInst, BoundsInst);
if (BoundsSigned) {
// Don't allow a negative bounds.
llvm::Value *Cmp = Builder.CreateICmpSGT(
BoundsVal, llvm::ConstantInt::get(BoundsVal->getType(), 0));
Check = Builder.CreateAnd(Cmp, Check);
}
EmitCheck(std::make_pair(Check, CheckKind), CheckHandler, StaticData,
IndexInst);
}
llvm::MDNode *CodeGenFunction::buildAllocToken(QualType AllocType) {
@ -4608,9 +4630,10 @@ static std::optional<int64_t> getOffsetDifferenceInBits(CodeGenFunction &CGF,
/// i.e. "a.b.count", so we shouldn't need the full force of EmitLValue or
/// similar to emit the correct GEP.
void CodeGenFunction::EmitCountedByBoundsChecking(
const Expr *E, llvm::Value *Idx, Address Addr, QualType IdxTy,
QualType ArrayTy, bool Accessed, bool FlexibleArray) {
const auto *ME = dyn_cast<MemberExpr>(E->IgnoreImpCasts());
const Expr *ArrayExpr, QualType ArrayType, Address ArrayInst,
QualType IndexType, llvm::Value *IndexVal, bool Accessed,
bool FlexibleArray) {
const auto *ME = dyn_cast<MemberExpr>(ArrayExpr->IgnoreImpCasts());
if (!ME || !ME->getMemberDecl()->getType()->isCountAttributedType())
return;
@ -4627,11 +4650,11 @@ void CodeGenFunction::EmitCountedByBoundsChecking(
if (std::optional<int64_t> Diff =
getOffsetDifferenceInBits(*this, CountFD, FD)) {
if (!Addr.isValid()) {
if (!ArrayInst.isValid()) {
// An invalid Address indicates we're checking a pointer array access.
// Emit the checked L-Value here.
LValue LV = EmitCheckedLValue(E, TCK_MemberAccess);
Addr = LV.getAddress();
LValue LV = EmitCheckedLValue(ArrayExpr, TCK_MemberAccess);
ArrayInst = LV.getAddress();
}
// FIXME: The 'static_cast' is necessary, otherwise the result turns into a
@ -4640,17 +4663,19 @@ void CodeGenFunction::EmitCountedByBoundsChecking(
// Create a GEP with the byte offset between the counted object and the
// count and use that to load the count value.
Addr = Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, Int8PtrTy, Int8Ty);
ArrayInst = Builder.CreatePointerBitCastOrAddrSpaceCast(ArrayInst,
Int8PtrTy, Int8Ty);
llvm::Type *CountTy = ConvertType(CountFD->getType());
llvm::Value *Res =
Builder.CreateInBoundsGEP(Int8Ty, Addr.emitRawPointer(*this),
llvm::Type *BoundsType = ConvertType(CountFD->getType());
llvm::Value *BoundsVal =
Builder.CreateInBoundsGEP(Int8Ty, ArrayInst.emitRawPointer(*this),
Builder.getInt32(*Diff), ".counted_by.gep");
Res = Builder.CreateAlignedLoad(CountTy, Res, getIntAlign(),
".counted_by.load");
BoundsVal = Builder.CreateAlignedLoad(BoundsType, BoundsVal, getIntAlign(),
".counted_by.load");
// Now emit the bounds checking.
EmitBoundsCheckImpl(E, Res, Idx, IdxTy, ArrayTy, Accessed);
EmitBoundsCheckImpl(ArrayExpr, ArrayType, IndexVal, IndexType, BoundsVal,
CountFD->getType(), Accessed);
}
}
@ -4796,9 +4821,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
if (SanOpts.has(SanitizerKind::ArrayBounds))
EmitCountedByBoundsChecking(Array, Idx, ArrayLV.getAddress(),
E->getIdx()->getType(), Array->getType(),
Accessed, /*FlexibleArray=*/true);
EmitCountedByBoundsChecking(Array, Array->getType(), ArrayLV.getAddress(),
E->getIdx()->getType(), Idx, Accessed,
/*FlexibleArray=*/true);
// Propagate the alignment from the array itself to the result.
QualType arrayType = Array->getType();
@ -4850,8 +4875,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
if (const auto *CE = dyn_cast_if_present<CastExpr>(Base);
CE && CE->getCastKind() == CK_LValueToRValue)
EmitCountedByBoundsChecking(CE, Idx, Address::invalid(),
E->getIdx()->getType(), ptrType, Accessed,
EmitCountedByBoundsChecking(CE, ptrType, Address::invalid(),
E->getIdx()->getType(), Idx, Accessed,
/*FlexibleArray=*/false);
}
}

View File

@ -3339,11 +3339,12 @@ public:
/// Emit a check that \p Base points into an array object, which
/// we can access at index \p Index. \p Accessed should be \c false if we
/// this expression is used as an lvalue, for instance in "&Arr[Idx]".
void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index,
QualType IndexType, bool Accessed);
void EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
llvm::Value *Index, QualType IndexType,
QualType IndexedType, bool Accessed);
void EmitBoundsCheck(const Expr *ArrayExpr, const Expr *ArrayExprBase,
llvm::Value *Index, QualType IndexType, bool Accessed);
void EmitBoundsCheckImpl(const Expr *ArrayExpr, QualType ArrayBaseType,
llvm::Value *IndexVal, QualType IndexType,
llvm::Value *BoundsVal, QualType BoundsType,
bool Accessed);
/// Returns debug info, with additional annotation if
/// CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo[Ordinal] is enabled for
@ -3372,9 +3373,9 @@ public:
// Emit bounds checking for flexible array and pointer members with the
// counted_by attribute.
void EmitCountedByBoundsChecking(const Expr *E, llvm::Value *Idx,
Address Addr, QualType IdxTy,
QualType ArrayTy, bool Accessed,
void EmitCountedByBoundsChecking(const Expr *ArrayExpr, QualType ArrayType,
Address ArrayInst, QualType IndexType,
llvm::Value *IndexVal, bool Accessed,
bool FlexibleArray);
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,

View File

@ -30,19 +30,21 @@ struct annotated_ptr {
// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test1(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], ptr noundef [[VALUE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// SANITIZE-WITH-ATTR-NEXT: [[ENTRY:.*:]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 8
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META6:![0-9]+]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7:![0-9]+]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ult i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6:![0-9]+]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7:![0-9]+]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]:
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR3:[0-9]+]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB2:[0-9]+]], i64 [[TMP3]]) #[[ATTR3:[0-9]+]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[CONT10]]:
// SANITIZE-WITH-ATTR-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA8:![0-9]+]]
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP2]], i64 [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA8:![0-9]+]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP4]], i64 [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: store ptr [[VALUE]], ptr [[ARRAYIDX]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA14:![0-9]+]]
// SANITIZE-WITH-ATTR-NEXT: ret void
//
@ -83,19 +85,21 @@ void test1(struct annotated_ptr *p, int index, struct foo *value) {
// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test2(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], ptr noundef [[VALUE:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: [[ENTRY:.*:]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 8
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ult i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]:
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[CONT10]]:
// SANITIZE-WITH-ATTR-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA8]]
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP2]], i64 [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA8]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP4]], i64 [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: store ptr [[VALUE]], ptr [[ARRAYIDX]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA14]]
// SANITIZE-WITH-ATTR-NEXT: ret void
//
@ -136,19 +140,21 @@ void test2(struct annotated_ptr *p, int index, struct foo *value) {
// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test3(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], ptr noundef [[VALUE:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: [[ENTRY:.*:]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 8
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[DOTNOT:%.*]] = icmp ugt i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[DOTNOT]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], label %[[CONT10:.*]], !prof [[PROF16:![0-9]+]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ule i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]:
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[CONT10]]:
// SANITIZE-WITH-ATTR-NEXT: [[BUF:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA8]]
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP1]], i64 [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = load ptr, ptr [[BUF]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA8]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds ptr, ptr [[TMP4]], i64 [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: store ptr [[VALUE]], ptr [[ARRAYIDX]], align 8, !tbaa [[_ZTS3FOOPTR_TBAA14]]
// SANITIZE-WITH-ATTR-NEXT: ret void
//
@ -258,24 +264,25 @@ size_t test5(struct annotated_ptr *p, int index) {
return __bdos((struct foo **)((char *)p->buf));
}
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 17179869177) i64 @test6(
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -17179869168, 34359738361) i64 @test6(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: [[ENTRY:.*:]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[DOTNOT:%.*]] = icmp ugt i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[DOTNOT]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], label %[[CONT8:.*]], !prof [[PROF16]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ule i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT8:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]:
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB6:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[CONT8]]:
// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[DOTCOUNTED_BY_LOAD]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = sub nsw i64 [[COUNT]], [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.smax.i64(i64 [[TMP1]], i64 0)
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = shl nuw nsw i64 [[TMP2]], 3
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP3]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = zext nneg i32 [[DOTCOUNTED_BY_LOAD]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = sub nsw i64 [[COUNT]], [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = shl nsw i64 [[TMP4]], 3
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[RESULT]]
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -34359738360, 34359738361) i64 @test6(
// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] {
@ -309,14 +316,15 @@ size_t test6(struct annotated_ptr *p, int index) {
// SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test7(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: [[ENTRY:.*:]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 8
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP1]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ult i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT10:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]:
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB7:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB7:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[CONT10]]:
// SANITIZE-WITH-ATTR-NEXT: ret i64 -1
@ -378,23 +386,24 @@ size_t test8(struct annotated_sized_ptr *p, int index) {
return __bdos(p->buf);
}
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test9(
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -2147483646, 4294967296) i64 @test9(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: [[ENTRY:.*:]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[DOTNOT:%.*]] = icmp ugt i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[DOTNOT]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], label %[[CONT8:.*]], !prof [[PROF16]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ule i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT8:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]:
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB9:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB9:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[CONT8]]:
// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[DOTCOUNTED_BY_LOAD]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = zext nneg i32 [[DOTCOUNTED_BY_LOAD]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = sub nsw i64 [[COUNT]], [[IDXPROM]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.smax.i64(i64 [[RESULT]], i64 0)
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[RESULT]]
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -4294967295, 4294967296) i64 @test9(
// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] {
@ -424,24 +433,26 @@ size_t test9(struct annotated_sized_ptr *p, int index) {
return __bdos(&p->buf[index]);
}
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test10(
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 10737418240) i64 @test10(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SANITIZE-WITH-ATTR-NEXT: [[ENTRY:.*:]]
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16
// SANITIZE-WITH-ATTR-NEXT: [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 4
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[DOTNOT:%.*]] = icmp ugt i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[DOTNOT]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], label %[[CONT8:.*]], !prof [[PROF16]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp ule i32 [[INDEX]], [[DOTCOUNTED_BY_LOAD]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[DOTCOUNTED_BY_LOAD]], 0, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: br i1 [[TMP2]], label %[[CONT8:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[HANDLER_OUT_OF_BOUNDS]]:
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB11:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB11:[0-9]+]], i64 [[TMP3]]) #[[ATTR3]], !nosanitize [[META6]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META6]]
// SANITIZE-WITH-ATTR: [[CONT8]]:
// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[DOTCOUNTED_BY_LOAD]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[INDEX_SIZE:%.*]] = shl nuw nsw i64 [[IDXPROM]], 2
// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = zext nneg i32 [[DOTCOUNTED_BY_LOAD]] to i64
// SANITIZE-WITH-ATTR-NEXT: [[INDEX_SIZE:%.*]] = shl nsw i64 [[IDXPROM]], 2
// SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = sub nsw i64 [[COUNT]], [[INDEX_SIZE]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.smax.i64(i64 [[RESULT]], i64 0)
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
// SANITIZE-WITH-ATTR-NEXT: [[TMP4:%.*]] = tail call i64 @llvm.smax.i64(i64 [[RESULT]], i64 0)
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP4]]
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -10737418236, 10737418240) i64 @test10(
// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] {
@ -562,7 +573,6 @@ size_t test12(struct pr151236_struct *p) {
// SANITIZE-WITH-ATTR: [[META13]] = !{!"any pointer", [[META4]], i64 0}
// SANITIZE-WITH-ATTR: [[_ZTS3FOOPTR_TBAA14]] = !{[[META15:![0-9]+]], [[META15]], i64 0}
// SANITIZE-WITH-ATTR: [[META15]] = !{!"p1 _ZTS3foo", [[META13]], i64 0}
// SANITIZE-WITH-ATTR: [[PROF16]] = !{!"branch_weights", i32 1, i32 1048575}
//.
// NO-SANITIZE-WITH-ATTR: [[META3:![0-9]+]] = !{!"int", [[META4:![0-9]+]], i64 0}
// NO-SANITIZE-WITH-ATTR: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}

File diff suppressed because it is too large Load Diff

View File

@ -25,8 +25,8 @@ void d(double*);
// CHECK-TRAP-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 10, !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-TRAP-NEXT: br i1 [[TMP1]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG23]], !prof [[PROF27:![0-9]+]], !nosanitize [[META10]]
// CHECK-TRAP: [[TRAP]]:
// CHECK-TRAP-NEXT: call void @llvm.ubsantrap(i8 18) #[[ATTR3:[0-9]+]], !dbg [[DBGTRAP:![0-9]+]], !nosanitize [[META10]]
// CHECK-TRAP-NEXT: unreachable, !dbg [[DBGTRAP]], !nosanitize [[META10]]
// CHECK-TRAP-NEXT: call void @llvm.ubsantrap(i8 18) #[[ATTR3:[0-9]+]], !dbg [[DBG28:![0-9]+]], !nosanitize [[META10]]
// CHECK-TRAP-NEXT: unreachable, !dbg [[DBG28]], !nosanitize [[META10]]
// CHECK-TRAP: [[CONT]]:
// CHECK-TRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG26:![0-9]+]]
// CHECK-TRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG26]]
@ -51,14 +51,13 @@ void d(double*);
// CHECK-NOTRAP-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 10, !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-NOTRAP-NEXT: br i1 [[TMP1]], label %[[CONT:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !dbg [[DBG23]], !prof [[PROF27:![0-9]+]], !nosanitize [[META10]]
// CHECK-NOTRAP: [[HANDLER_OUT_OF_BOUNDS]]:
// CHECK-NOTRAP-NEXT: [[TMP2:%.*]] = zext i32 [[CALL]] to i64, !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-NOTRAP-NEXT: call void @__ubsan_handle_out_of_bounds_abort(ptr @[[GLOB2:[0-9]+]], i64 [[TMP2]]) #[[ATTR3:[0-9]+]], !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-NOTRAP-NEXT: call void @__ubsan_handle_out_of_bounds_abort(ptr @[[GLOB2:[0-9]+]], i64 [[TMP0]]) #[[ATTR3:[0-9]+]], !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-NOTRAP-NEXT: unreachable, !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-NOTRAP: [[CONT]]:
// CHECK-NOTRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG26:![0-9]+]]
// CHECK-NOTRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG26]]
// CHECK-NOTRAP-NEXT: [[TMP3:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG26]]
// CHECK-NOTRAP-NEXT: ret double [[TMP3]], !dbg [[DBG28:![0-9]+]]
// CHECK-NOTRAP-NEXT: [[TMP2:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG26]]
// CHECK-NOTRAP-NEXT: ret double [[TMP2]], !dbg [[DBG28:![0-9]+]]
//
double f1(int b, int i) {
double a[10];
@ -68,60 +67,60 @@ double f1(int b, int i) {
//.
// CHECK-TRAP: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
// CHECK-TRAP: [[META1]] = !DIFile(filename: "<stdin>", directory: {{.*}})
// CHECK-TRAP: [[DBG4]] = distinct !DISubprogram(name: "f1", scope: [[META5:![0-9]+]], file: [[META5]], line: 63, type: [[META6:![0-9]+]], scopeLine: 63, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META10]])
// CHECK-TRAP: [[META5]] = !DIFile(filename: "bounds-checking-debuginfo.c", directory: {{.*}})
// CHECK-TRAP: [[META1]] = !DIFile(filename: "{{.*}}<stdin>", directory: {{.*}})
// CHECK-TRAP: [[DBG4]] = distinct !DISubprogram(name: "f1", scope: [[META5:![0-9]+]], file: [[META5]], line: 62, type: [[META6:![0-9]+]], scopeLine: 62, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META10]])
// CHECK-TRAP: [[META5]] = !DIFile(filename: "{{.*}}bounds-checking-debuginfo.c", directory: {{.*}})
// CHECK-TRAP: [[META6]] = !DISubroutineType(types: [[META7:![0-9]+]])
// CHECK-TRAP: [[META7]] = !{[[META8:![0-9]+]], [[META9:![0-9]+]], [[META9]]}
// CHECK-TRAP: [[META8]] = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
// CHECK-TRAP: [[META9]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
// CHECK-TRAP: [[META10]] = !{}
// CHECK-TRAP: [[META11]] = !DILocalVariable(name: "b", arg: 1, scope: [[DBG4]], file: [[META5]], line: 63, type: [[META9]])
// CHECK-TRAP: [[META12]] = !DILocation(line: 63, column: 15, scope: [[DBG4]])
// CHECK-TRAP: [[META13]] = !DILocalVariable(name: "i", arg: 2, scope: [[DBG4]], file: [[META5]], line: 63, type: [[META9]])
// CHECK-TRAP: [[META14]] = !DILocation(line: 63, column: 22, scope: [[DBG4]])
// CHECK-TRAP: [[META15]] = !DILocalVariable(name: "a", scope: [[DBG4]], file: [[META5]], line: 64, type: [[META16:![0-9]+]])
// CHECK-TRAP: [[META11]] = !DILocalVariable(name: "b", arg: 1, scope: [[DBG4]], file: [[META5]], line: 62, type: [[META9]])
// CHECK-TRAP: [[META12]] = !DILocation(line: 62, column: 15, scope: [[DBG4]])
// CHECK-TRAP: [[META13]] = !DILocalVariable(name: "i", arg: 2, scope: [[DBG4]], file: [[META5]], line: 62, type: [[META9]])
// CHECK-TRAP: [[META14]] = !DILocation(line: 62, column: 22, scope: [[DBG4]])
// CHECK-TRAP: [[META15]] = !DILocalVariable(name: "a", scope: [[DBG4]], file: [[META5]], line: 63, type: [[META16:![0-9]+]])
// CHECK-TRAP: [[META16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: [[META8]], size: 640, elements: [[META17:![0-9]+]])
// CHECK-TRAP: [[META17]] = !{[[META18:![0-9]+]]}
// CHECK-TRAP: [[META18]] = !DISubrange(count: 10)
// CHECK-TRAP: [[META19]] = !DILocation(line: 64, column: 10, scope: [[DBG4]])
// CHECK-TRAP: [[DBG20]] = !DILocation(line: 65, column: 5, scope: [[DBG4]])
// CHECK-TRAP: [[DBG21]] = !DILocation(line: 65, column: 3, scope: [[DBG4]])
// CHECK-TRAP: [[DBG22]] = !DILocation(line: 66, column: 12, scope: [[DBG4]])
// CHECK-TRAP: [[META19]] = !DILocation(line: 63, column: 10, scope: [[DBG4]])
// CHECK-TRAP: [[DBG20]] = !DILocation(line: 64, column: 5, scope: [[DBG4]])
// CHECK-TRAP: [[DBG21]] = !DILocation(line: 64, column: 3, scope: [[DBG4]])
// CHECK-TRAP: [[DBG22]] = !DILocation(line: 65, column: 12, scope: [[DBG4]])
// CHECK-TRAP: [[DBG23]] = !DILocation(line: 0, scope: [[META24:![0-9]+]], inlinedAt: [[DBG26]])
// CHECK-TRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array_bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
// CHECK-TRAP: [[META25]] = !DISubroutineType(types: null)
// CHECK-TRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
// CHECK-TRAP: [[DBG26]] = !DILocation(line: 65, column: 10, scope: [[DBG4]])
// CHECK-TRAP: [[PROF27]] = !{!"branch_weights", i32 1048575, i32 1}
// CHECK-TRAP: [[DBGTRAP]] = !DILocation(line: 0, scope: [[TRAPMSG:![0-9]+]], inlinedAt: [[DBG23]])
// CHECK-TRAP: [[TRAPMSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Array index out of bounds", scope: [[META5]], file: [[META5]], type: [[META25]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
// CHECK-TRAP: [[DBG30]] = !DILocation(line: 66, column: 3, scope: [[DBG4]])
// CHECK-TRAP: [[DBG28]] = !DILocation(line: 0, scope: [[META29:![0-9]+]], inlinedAt: [[DBG23]])
// CHECK-TRAP: [[META29]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Array index out of bounds", scope: [[META5]], file: [[META5]], type: [[META25]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
// CHECK-TRAP: [[DBG30]] = !DILocation(line: 65, column: 3, scope: [[DBG4]])
//.
// CHECK-NOTRAP: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
// CHECK-NOTRAP: [[META1]] = !DIFile(filename: "<stdin>", directory: {{.*}})
// CHECK-NOTRAP: [[DBG4]] = distinct !DISubprogram(name: "f1", scope: [[META5:![0-9]+]], file: [[META5]], line: 63, type: [[META6:![0-9]+]], scopeLine: 63, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META10]])
// CHECK-NOTRAP: [[META5]] = !DIFile(filename: "bounds-checking-debuginfo.c", directory: {{.*}})
// CHECK-NOTRAP: [[META1]] = !DIFile(filename: "{{.*}}<stdin>", directory: {{.*}})
// CHECK-NOTRAP: [[DBG4]] = distinct !DISubprogram(name: "f1", scope: [[META5:![0-9]+]], file: [[META5]], line: 62, type: [[META6:![0-9]+]], scopeLine: 62, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META10]])
// CHECK-NOTRAP: [[META5]] = !DIFile(filename: "{{.*}}bounds-checking-debuginfo.c", directory: {{.*}})
// CHECK-NOTRAP: [[META6]] = !DISubroutineType(types: [[META7:![0-9]+]])
// CHECK-NOTRAP: [[META7]] = !{[[META8:![0-9]+]], [[META9:![0-9]+]], [[META9]]}
// CHECK-NOTRAP: [[META8]] = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
// CHECK-NOTRAP: [[META9]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
// CHECK-NOTRAP: [[META10]] = !{}
// CHECK-NOTRAP: [[META11]] = !DILocalVariable(name: "b", arg: 1, scope: [[DBG4]], file: [[META5]], line: 63, type: [[META9]])
// CHECK-NOTRAP: [[META12]] = !DILocation(line: 63, column: 15, scope: [[DBG4]])
// CHECK-NOTRAP: [[META13]] = !DILocalVariable(name: "i", arg: 2, scope: [[DBG4]], file: [[META5]], line: 63, type: [[META9]])
// CHECK-NOTRAP: [[META14]] = !DILocation(line: 63, column: 22, scope: [[DBG4]])
// CHECK-NOTRAP: [[META15]] = !DILocalVariable(name: "a", scope: [[DBG4]], file: [[META5]], line: 64, type: [[META16:![0-9]+]])
// CHECK-NOTRAP: [[META11]] = !DILocalVariable(name: "b", arg: 1, scope: [[DBG4]], file: [[META5]], line: 62, type: [[META9]])
// CHECK-NOTRAP: [[META12]] = !DILocation(line: 62, column: 15, scope: [[DBG4]])
// CHECK-NOTRAP: [[META13]] = !DILocalVariable(name: "i", arg: 2, scope: [[DBG4]], file: [[META5]], line: 62, type: [[META9]])
// CHECK-NOTRAP: [[META14]] = !DILocation(line: 62, column: 22, scope: [[DBG4]])
// CHECK-NOTRAP: [[META15]] = !DILocalVariable(name: "a", scope: [[DBG4]], file: [[META5]], line: 63, type: [[META16:![0-9]+]])
// CHECK-NOTRAP: [[META16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: [[META8]], size: 640, elements: [[META17:![0-9]+]])
// CHECK-NOTRAP: [[META17]] = !{[[META18:![0-9]+]]}
// CHECK-NOTRAP: [[META18]] = !DISubrange(count: 10)
// CHECK-NOTRAP: [[META19]] = !DILocation(line: 64, column: 10, scope: [[DBG4]])
// CHECK-NOTRAP: [[DBG20]] = !DILocation(line: 65, column: 5, scope: [[DBG4]])
// CHECK-NOTRAP: [[DBG21]] = !DILocation(line: 65, column: 3, scope: [[DBG4]])
// CHECK-NOTRAP: [[DBG22]] = !DILocation(line: 66, column: 12, scope: [[DBG4]])
// CHECK-NOTRAP: [[META19]] = !DILocation(line: 63, column: 10, scope: [[DBG4]])
// CHECK-NOTRAP: [[DBG20]] = !DILocation(line: 64, column: 5, scope: [[DBG4]])
// CHECK-NOTRAP: [[DBG21]] = !DILocation(line: 64, column: 3, scope: [[DBG4]])
// CHECK-NOTRAP: [[DBG22]] = !DILocation(line: 65, column: 12, scope: [[DBG4]])
// CHECK-NOTRAP: [[DBG23]] = !DILocation(line: 0, scope: [[META24:![0-9]+]], inlinedAt: [[DBG26]])
// CHECK-NOTRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array_bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
// CHECK-NOTRAP: [[META25]] = !DISubroutineType(types: null)
// CHECK-NOTRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
// CHECK-NOTRAP: [[DBG26]] = !DILocation(line: 65, column: 10, scope: [[DBG4]])
// CHECK-NOTRAP: [[PROF27]] = !{!"branch_weights", i32 1048575, i32 1}
// CHECK-NOTRAP: [[DBG28]] = !DILocation(line: 66, column: 3, scope: [[DBG4]])
// CHECK-NOTRAP: [[DBG28]] = !DILocation(line: 65, column: 3, scope: [[DBG4]])
//.