diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index ffc2f35c2bdb2..f636c9b39d9a3 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -516,7 +516,7 @@ VisitBoundsSafetyPointerPromotionExpr(BoundsSafetyPointerPromotionExpr *E) { Ptr = CGF.GetWidePointerElement(PtrRV.getAggregateAddress(), WPIndex::Pointer); } - llvm::BranchInst *NullCheckBranch = nullptr; + llvm::BasicBlock *NullBlock = nullptr; if (E->getNullCheck()) { // Test that the pointer is not NULL before testing that it's in bounds, // if AcceptNullPtr is specified. @@ -525,7 +525,8 @@ VisitBoundsSafetyPointerPromotionExpr(BoundsSafetyPointerPromotionExpr *E) { llvm::Value *Null = llvm::Constant::getNullValue(Ptr->getType()); llvm::Value *PtrIsNull = Builder.CreateICmpNE(Ptr, Null); - NullCheckBranch = Builder.CreateCondBr(PtrIsNull, NotNull, nullptr); + NullBlock = CGF.createBasicBlock("boundscheck.null"); + Builder.CreateCondBr(PtrIsNull, NotNull, NullBlock); CGF.EmitBlock(NotNull); } @@ -573,12 +574,10 @@ VisitBoundsSafetyPointerPromotionExpr(BoundsSafetyPointerPromotionExpr *E) { // fill result with null // br cont // cont: - if (NullCheckBranch) { + if (NullBlock) { llvm::BasicBlock *ContBlock = CGF.createBasicBlock("boundscheck.cont"); Builder.CreateBr(ContBlock); - llvm::BasicBlock *NullBlock = CGF.createBasicBlock("boundscheck.null"); - NullCheckBranch->setSuccessor(1, NullBlock); CGF.EmitBlock(NullBlock); llvm::Value *Zero = llvm::Constant::getNullValue(Ptr->getType()); EmitWidePointerToDest(E->getType(), Zero, Zero, Zero, Callback); diff --git a/clang/test/BoundsSafety/CodeGen/loop-counted_by_or_null-O0.c b/clang/test/BoundsSafety/CodeGen/loop-counted_by_or_null-O0.c new file mode 100644 index 0000000000000..9c0f14f180cb6 --- /dev/null +++ b/clang/test/BoundsSafety/CodeGen/loop-counted_by_or_null-O0.c @@ -0,0 +1,74 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 +// REQUIRES: system-darwin + +// RUN: %clang_cc1 -O0 -triple arm64-apple-iphoneos -emit-llvm -fbounds-safety -o - %s | FileCheck %s + +// Exercise the null check path inside a loop. This used to crash the compiler. + +#include + +void use(int *__bidi_indexable q); + +// CHECK-LABEL: define dso_local void @f( +// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[LEN:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[LEN_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[Q:%.*]] = alloca %"__bounds_safety::wide_ptr.bidi_indexable", align 8 +// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca %"__bounds_safety::wide_ptr.bidi_indexable", align 8 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 8 +// CHECK-NEXT: store i32 [[LEN]], ptr [[LEN_ADDR]], align 4 +// CHECK-NEXT: store i32 0, ptr [[I]], align 4 +// CHECK-NEXT: br label %[[FOR_COND:.*]] +// CHECK: [[FOR_COND]]: +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[LEN_ADDR]], align 4 +// CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP0]], [[TMP1]] +// CHECK-NEXT: br i1 [[CMP]], label %[[FOR_BODY:.*]], label %[[FOR_END:.*]] +// CHECK: [[FOR_BODY]]: +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[P_ADDR]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[LEN_ADDR]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = icmp ne ptr [[TMP2]], null, !annotation [[META4:![0-9]+]] +// CHECK-NEXT: br i1 [[TMP4]], label %[[BOUNDSCHECK_NOTNULL:.*]], label %[[BOUNDSCHECK_NULL:.*]], !annotation [[META4]] +// CHECK: [[BOUNDSCHECK_NOTNULL]]: +// CHECK-NEXT: [[IDX_EXT:%.*]] = sext i32 [[TMP3]] to i64 +// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i64 [[IDX_EXT]] +// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds nuw %"__bounds_safety::wide_ptr.bidi_indexable", ptr [[Q]], i32 0, i32 0 +// CHECK-NEXT: store ptr [[TMP2]], ptr [[TMP5]], align 8 +// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds nuw %"__bounds_safety::wide_ptr.bidi_indexable", ptr [[Q]], i32 0, i32 1 +// CHECK-NEXT: store ptr [[ADD_PTR]], ptr [[TMP6]], align 8 +// CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds nuw %"__bounds_safety::wide_ptr.bidi_indexable", ptr [[Q]], i32 0, i32 2 +// CHECK-NEXT: store ptr [[TMP2]], ptr [[TMP7]], align 8 +// CHECK-NEXT: br label %[[BOUNDSCHECK_CONT:.*]] +// CHECK: [[BOUNDSCHECK_NULL]]: +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds nuw %"__bounds_safety::wide_ptr.bidi_indexable", ptr [[Q]], i32 0, i32 0 +// CHECK-NEXT: store ptr null, ptr [[TMP8]], align 8 +// CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds nuw %"__bounds_safety::wide_ptr.bidi_indexable", ptr [[Q]], i32 0, i32 1 +// CHECK-NEXT: store ptr null, ptr [[TMP9]], align 8 +// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds nuw %"__bounds_safety::wide_ptr.bidi_indexable", ptr [[Q]], i32 0, i32 2 +// CHECK-NEXT: store ptr null, ptr [[TMP10]], align 8 +// CHECK-NEXT: br label %[[BOUNDSCHECK_CONT]] +// CHECK: [[BOUNDSCHECK_CONT]]: +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[BYVAL_TEMP]], ptr align 8 [[Q]], i64 24, i1 false) +// CHECK-NEXT: call void @use(ptr noundef align 8 dead_on_return [[BYVAL_TEMP]]) +// CHECK-NEXT: br label %[[FOR_INC:.*]] +// CHECK: [[FOR_INC]]: +// CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4 +// CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP11]], 1 +// CHECK-NEXT: store i32 [[INC]], ptr [[I]], align 4 +// CHECK-NEXT: br label %[[FOR_COND]], !llvm.loop [[LOOP5:![0-9]+]] +// CHECK: [[FOR_END]]: +// CHECK-NEXT: ret void +// +void f(int *__counted_by_or_null(len) p, int len) { + for (int i = 0; i < len; ++i) { + int *__bidi_indexable q = p; + use(q); + } +} +//. +// CHECK: [[META4]] = !{!"bounds-safety-check-ptr-neq-null"} +// CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[META6:![0-9]+]]} +// CHECK: [[META6]] = !{!"llvm.loop.mustprogress"} +//. diff --git a/clang/test/BoundsSafety/CodeGen/loop-counted_by_or_null-O2.c b/clang/test/BoundsSafety/CodeGen/loop-counted_by_or_null-O2.c new file mode 100644 index 0000000000000..fb2c3795e2252 --- /dev/null +++ b/clang/test/BoundsSafety/CodeGen/loop-counted_by_or_null-O2.c @@ -0,0 +1,55 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 +// REQUIRES: system-darwin + +// RUN: %clang_cc1 -O2 -triple arm64-apple-iphoneos -emit-llvm -fbounds-safety -o - %s | FileCheck %s + +// Exercise the null check path inside a loop. This used to crash the compiler. + +#include + +void use(int *__bidi_indexable q); + +// CHECK-LABEL: define dso_local void @f( +// CHECK-SAME: ptr noundef [[P:%.*]], i32 noundef [[LEN:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca %"__bounds_safety::wide_ptr.bidi_indexable", align 8 +// CHECK-NEXT: [[CMP3:%.*]] = icmp sgt i32 [[LEN]], 0 +// CHECK-NEXT: br i1 [[CMP3]], label %[[FOR_BODY_LR_PH:.*]], label %[[FOR_COND_CLEANUP:.*]] +// CHECK: [[FOR_BODY_LR_PH]]: +// CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq ptr [[P]], null, !annotation [[META9:![0-9]+]] +// CHECK-NEXT: [[IDX_EXT:%.*]] = zext nneg i32 [[LEN]] to i64 +// CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds nuw [4 x i8], ptr [[P]], i64 [[IDX_EXT]] +// CHECK-NEXT: [[Q_SROA_5_0:%.*]] = select i1 [[DOTNOT]], ptr null, ptr [[ADD_PTR]] +// CHECK-NEXT: [[Q_SROA_5_0_BYVAL_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[BYVAL_TEMP]], i64 8 +// CHECK-NEXT: [[Q_SROA_7_0_BYVAL_TEMP_SROA_IDX:%.*]] = getelementptr inbounds nuw i8, ptr [[BYVAL_TEMP]], i64 16 +// CHECK-NEXT: br label %[[FOR_BODY:.*]] +// CHECK: [[FOR_COND_CLEANUP]]: +// CHECK-NEXT: ret void +// CHECK: [[FOR_BODY]]: +// CHECK-NEXT: [[I_04:%.*]] = phi i32 [ 0, %[[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], %[[FOR_BODY]] ] +// CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr nonnull [[BYVAL_TEMP]]) #[[ATTR3:[0-9]+]] +// CHECK-NEXT: store ptr [[P]], ptr [[BYVAL_TEMP]], align 8 +// CHECK-NEXT: store ptr [[Q_SROA_5_0]], ptr [[Q_SROA_5_0_BYVAL_TEMP_SROA_IDX]], align 8 +// CHECK-NEXT: store ptr [[P]], ptr [[Q_SROA_7_0_BYVAL_TEMP_SROA_IDX]], align 8, !tbaa [[INTPTR_TBAA10:![0-9]+]] +// CHECK-NEXT: call void @use(ptr noundef nonnull align 8 dead_on_return [[BYVAL_TEMP]]) #[[ATTR3]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0(ptr nonnull [[BYVAL_TEMP]]) #[[ATTR3]] +// CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_04]], 1 +// CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i32 [[INC]], [[LEN]] +// CHECK-NEXT: br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP13:![0-9]+]] +// +void f(int *__counted_by_or_null(len) p, int len) { + for (int i = 0; i < len; ++i) { + int *__bidi_indexable q = p; + use(q); + } +} +//. +// CHECK: [[META7:![0-9]+]] = !{!"omnipotent char", [[META8:![0-9]+]], i64 0} +// CHECK: [[META8]] = !{!"Simple C/C++ TBAA"} +// CHECK: [[META9]] = !{!"bounds-safety-check-ptr-neq-null"} +// CHECK: [[INTPTR_TBAA10]] = !{[[META11:![0-9]+]], [[META11]], i64 0} +// CHECK: [[META11]] = !{!"p1 int", [[META12:![0-9]+]], i64 0} +// CHECK: [[META12]] = !{!"any pointer", [[META7]], i64 0} +// CHECK: [[LOOP13]] = distinct !{[[LOOP13]], [[META14:![0-9]+]]} +// CHECK: [[META14]] = !{!"llvm.loop.mustprogress"} +//.