diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1249,7 +1249,7 @@ LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) { LValue LV; - if (SanOpts.has(SanitizerKind::ArrayBounds) && isa(E)) + if (isa(E)) LV = EmitArraySubscriptExpr(cast(E), /*Accessed*/true); else LV = EmitLValue(E); @@ -3691,6 +3691,32 @@ return Address(eltPtr, eltAlign); } +// Add range metadata: It is UB to subscript outside of the array, therefore +// array indices are known to be in range: +// * [0, indexing_bound) if the array is accessed. +// * [0, indexing_bound] if only address computation is preformed. +static llvm::Value *addArrayIndexingRangeMetadata(CodeGenFunction &CGF, + const Expr *Base, + llvm::Value *Idx, + bool Accessed) { + QualType IdxTy; + llvm::ConstantInt *Bound = dyn_cast_or_null( + getArrayIndexingBound(CGF, Base, IdxTy)); + if (Bound == nullptr) + return Idx; + llvm::Instruction *AnnotatedIdx = + CGF.Builder.CreateIntrinsic(llvm::Intrinsic::annotation, {Idx->getType()}, + {Idx, llvm::UndefValue::get(CGF.Int8PtrTy), + llvm::UndefValue::get(CGF.Int8PtrTy), + llvm::UndefValue::get(CGF.Int32Ty)}); + llvm::MDBuilder MDHelper(CGF.getLLVMContext()); + AnnotatedIdx->setMetadata( + llvm::LLVMContext::MD_range, + MDHelper.createRange(llvm::APInt(Bound->getBitWidth(), 0), + Bound->getValue() + (Accessed ? 0 : 1))); + return AnnotatedIdx; +} + LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, bool Accessed) { // The index must always be an integer, which is not an aggregate. Emit it @@ -3716,6 +3742,9 @@ if (Promote && Idx->getType() != IntPtrTy) Idx = Builder.CreateIntCast(Idx, IntPtrTy, IdxSigned, "idxprom"); + if (CGM.getCodeGenOpts().OptimizationLevel > 0) + Idx = addArrayIndexingRangeMetadata(*this, E->getBase(), Idx, Accessed); + return Idx; }; IdxPre = nullptr; diff --git a/clang/test/CodeGen/array-bounds.cpp b/clang/test/CodeGen/array-bounds.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/array-bounds.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s \ +// RUN: -emit-llvm -o - | FileCheck %s +// +// Check that we generate array bound information for accesses to array +// elements. + +struct A { int i; }; +struct B { A a[1]; }; +struct C { int i; int x[3]; }; +struct D { int i; int* x; }; +struct E { int x[3][5]; }; + +//TODO: std::array + +int deref(C *c, int j) { +// CHECK-LABEL: _Z5derefP1Ci +// CHECK: [[INDEX:%.*]] = call i64 @llvm.annotation{{.*}}, !range [[RANGE_0_3:!.*]] +// CHECK: getelementptr {{.*}} [[INDEX]] + return c->x[j]; +} + +int deref_noindex(B *b) { +// CHECK-LABEL: _Z13deref_noindexP1B +// CHECK-NOT: llvm.annotation +// CHECK: getelementptr {{.*}} + return b->a->i; +} + +int deref_ptr(D *d, int j) { +// CHECK-LABEL: _Z9deref_ptrP1Di +// CHECK-NOT: llvm.annotation +// CHECK: getelementptr {{.*}} + return d->x[j]; +} + +int deref_multi(E *e, int j, int k) { +// CHECK-LABEL: _Z11deref_multiP1Eii +// CHECK: [[INDEX1:%.*]] = call i64 @llvm.annotation{{.*}}, !range [[RANGE_0_3]] +// CHECK: getelementptr {{.*}} [[INDEX1]] +// CHECK: [[INDEX2:%.*]] = call i64 @llvm.annotation{{.*}}, !range [[RANGE_0_5:!.*]] +// CHECK: getelementptr {{.*}} [[INDEX2]] + return e->x[j][k]; +} + +// We are not dereferencing the computed address, it is valid to compute a +// past-the-end address. +int* addr(C *c, int j) { +// CHECK-LABEL: _Z4addrP1Ci +// CHECK: [[INDEX:%.*]] = call i64 @llvm.annotation{{.*}}, !range [[RANGE_0_4:!.*]] +// CHECK: getelementptr {{.*}} [[INDEX]] + return &c->x[j]; +} + +// CHECK-DAG: [[RANGE_0_3]] = !{i64 0, i64 3} +// CHECK-DAG: [[RANGE_0_4]] = !{i64 0, i64 4} +// CHECK-DAG: [[RANGE_0_5]] = !{i64 0, i64 5}