diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-02-23 02:53:19 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-02-23 02:53:19 +0000 |
commit | a0a628f839cf50844cc0f226bd9cb72485f98f91 (patch) | |
tree | 321e7ec506b6d97ff2d46889c5dbe7eb3ed4f505 /lib/CodeGen | |
parent | 1c8278b4bc83fafd29eead80ff4e5814fce7fd9b (diff) |
ubsan: Emit bounds checks for array indexing, vector indexing, and (in really simple cases) pointer arithmetic. This augments the existing bounds checking with language-level array bounds information.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175949 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 97 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 11 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 9 |
3 files changed, 112 insertions, 5 deletions
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index ba400b8a60..a688dbfacb 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -630,6 +630,83 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, } } +/// Determine whether this expression refers to a flexible array member in a +/// struct. We disable array bounds checks for such members. +static bool isFlexibleArrayMemberExpr(const Expr *E) { + // For compatibility with existing code, we treat arrays of length 0 or + // 1 as flexible array members. + const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe(); + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { + if (CAT->getSize().ugt(1)) + return false; + } else if (!isa<IncompleteArrayType>(AT)) + return false; + + E = E->IgnoreParens(); + + // A flexible array member must be the last member in the class. + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + // FIXME: If the base type of the member expr is not FD->getParent(), + // this should not be treated as a flexible array member access. + if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) { + RecordDecl::field_iterator FI( + DeclContext::decl_iterator(const_cast<FieldDecl *>(FD))); + return ++FI == FD->getParent()->field_end(); + } + } + + return false; +} + +/// If Base is known to point to the start of an array, return the length of +/// that array. Return 0 if the length cannot be determined. +llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, const Expr *Base, + QualType &IndexedType) { + // For the vector indexing extension, the bound is the number of elements. + if (const VectorType *VT = Base->getType()->getAs<VectorType>()) { + IndexedType = Base->getType(); + return CGF.Builder.getInt32(VT->getNumElements()); + } + + Base = Base->IgnoreParens(); + + if (const CastExpr *CE = dyn_cast<CastExpr>(Base)) { + if (CE->getCastKind() == CK_ArrayToPointerDecay && + !isFlexibleArrayMemberExpr(CE->getSubExpr())) { + IndexedType = CE->getSubExpr()->getType(); + const ArrayType *AT = IndexedType->castAsArrayTypeUnsafe(); + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) + return CGF.Builder.getInt(CAT->getSize()); + else if (const VariableArrayType *VAT = cast<VariableArrayType>(AT)) + return CGF.getVLASize(VAT).first; + } + } + + return 0; +} + +void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base, + llvm::Value *Index, QualType IndexType, + bool Accessed) { + QualType IndexedType; + llvm::Value *Bound = getArrayIndexingBound(*this, Base, IndexedType); + if (!Bound) + return; + + bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType(); + llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned); + llvm::Value *BoundVal = Builder.CreateIntCast(Bound, SizeTy, false); + + llvm::Constant *StaticData[] = { + EmitCheckSourceLocation(E->getExprLoc()), + EmitCheckTypeDescriptor(IndexedType), + EmitCheckTypeDescriptor(IndexType) + }; + llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexVal, BoundVal) + : Builder.CreateICmpULE(IndexVal, BoundVal); + EmitCheck(Check, "out_of_bounds", StaticData, Index, CRK_Recoverable); +} + CodeGenFunction::ComplexPairTy CodeGenFunction:: EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV, @@ -705,7 +782,11 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E, } LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) { - LValue LV = EmitLValue(E); + LValue LV; + if (SanOpts->Bounds && isa<ArraySubscriptExpr>(E)) + LV = EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E), /*Accessed*/true); + else + LV = EmitLValue(E); if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple()) EmitTypeCheck(TCK, E->getExprLoc(), LV.getAddress(), E->getType(), LV.getAlignment()); @@ -2121,12 +2202,16 @@ static const Expr *isSimpleArrayDecayOperand(const Expr *E) { return SubExpr; } -LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { +LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, + bool Accessed) { // The index must always be an integer, which is not an aggregate. Emit it. llvm::Value *Idx = EmitScalarExpr(E->getIdx()); QualType IdxTy = E->getIdx()->getType(); bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType(); + if (SanOpts->Bounds) + EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed); + // If the base is a vector type, then we are forming a vector element lvalue // with this subscript. if (E->getBase()->getType()->isVectorType()) { @@ -2187,7 +2272,13 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { // "gep x, i" here. Emit one "gep A, 0, i". assert(Array->getType()->isArrayType() && "Array to pointer decay must have array source type!"); - LValue ArrayLV = EmitLValue(Array); + LValue ArrayLV; + // For simple multidimensional array indexing, set the 'accessed' flag for + // better bounds-checking of the base expression. + if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Array)) + ArrayLV = EmitArraySubscriptExpr(ASE, /*Accessed*/ true); + else + ArrayLV = EmitLValue(Array); llvm::Value *ArrayPtr = ArrayLV.getAddress(); llvm::Value *Zero = llvm::ConstantInt::get(Int32Ty, 0); llvm::Value *Args[] = { Zero, Idx }; diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 69aa7e849c..d76cad2c56 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -986,7 +986,12 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { // integer value. Value *Base = Visit(E->getBase()); Value *Idx = Visit(E->getIdx()); - bool IdxSigned = E->getIdx()->getType()->isSignedIntegerOrEnumerationType(); + QualType IdxTy = E->getIdx()->getType(); + + if (CGF.SanOpts->Bounds) + CGF.EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, /*Accessed*/true); + + bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType(); Idx = Builder.CreateIntCast(Idx, CGF.Int32Ty, IdxSigned, "vecidxcast"); return Builder.CreateExtractElement(Base, Idx, "vecext"); } @@ -2134,6 +2139,10 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, if (isSubtraction) index = CGF.Builder.CreateNeg(index, "idx.neg"); + if (CGF.SanOpts->Bounds) + CGF.EmitBoundsCheck(op.E, pointerOperand, index, indexOperand->getType(), + /*Accessed*/ false); + const PointerType *pointerType = pointerOperand->getType()->getAs<PointerType>(); if (!pointerType) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index fce5c49950..880b82e924 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1910,6 +1910,12 @@ public: void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V, QualType Type, CharUnits Alignment = CharUnits::Zero()); + /// \brief 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); + llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV, @@ -2187,7 +2193,8 @@ public: LValue EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E); LValue EmitPredefinedLValue(const PredefinedExpr *E); LValue EmitUnaryOpLValue(const UnaryOperator *E); - LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E); + LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E, + bool Accessed = false); LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E); LValue EmitMemberExpr(const MemberExpr *E); LValue EmitObjCIsaExpr(const ObjCIsaExpr *E); |