From: Ted Kremenek Date: Fri, 24 Dec 2010 08:39:33 +0000 (+0000) Subject: Add basic support for pointer arithmetic in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a6b0b96e5376cd9cf182a3e240e0537feed43cde;p=clang Add basic support for pointer arithmetic in SimpleSValBuilder. This clears up some false positives emitted by ArrayBoundCheckerV2 due to the lack of support for pointer arithmetic. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122546 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h index 33779a9fd5..6ba3dc68fc 100644 --- a/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h @@ -357,7 +357,11 @@ public: virtual QualType getLocationType() const { // FIXME: We can possibly optimize this later to cache this value. - return getContext().getPointerType(getValueType()); + QualType T = getValueType(); + ASTContext &ctx = getContext(); + if (T->getAs()) + return ctx.getObjCObjectPointerType(T); + return ctx.getPointerType(getValueType()); } QualType getDesugaredValueType(ASTContext &Context) const { diff --git a/include/clang/StaticAnalyzer/PathSensitive/Store.h b/include/clang/StaticAnalyzer/PathSensitive/Store.h index c48f129feb..7054d64a38 100644 --- a/include/clang/StaticAnalyzer/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/PathSensitive/Store.h @@ -153,13 +153,6 @@ public: /// casted and 'CastToTy' the result type of the cast. const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy); - - /// evalBinOp - Perform pointer arithmetic. - virtual SVal evalBinOp(BinaryOperator::Opcode Op, - Loc lhs, NonLoc rhs, QualType resultTy) { - return UnknownVal(); - } - virtual Store RemoveDeadBindings(Store store, const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl& RegionRoots) = 0; diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index 17bc339f75..c522e72210 100644 --- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -2950,7 +2950,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, SVal RHS; if (U->getType()->isAnyPointerType()) - RHS = svalBuilder.makeIntValWithPtrWidth(1, false); + RHS = svalBuilder.makeArrayIndex(1); else RHS = svalBuilder.makeIntVal(1, U->getType()); diff --git a/lib/StaticAnalyzer/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/SimpleSValBuilder.cpp index f1a9074b95..a6432121f5 100644 --- a/lib/StaticAnalyzer/SimpleSValBuilder.cpp +++ b/lib/StaticAnalyzer/SimpleSValBuilder.cpp @@ -808,6 +808,11 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, SVal SimpleSValBuilder::evalBinOpLN(const GRState *state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy) { + + // Special case: rhs is a zero constant. + if (rhs.isZeroConstant()) + return lhs; + // Special case: 'rhs' is an integer that has the same width as a pointer and // we are using the integer location in a comparison. Normally this cannot be // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32 @@ -858,11 +863,39 @@ SVal SimpleSValBuilder::evalBinOpLN(const GRState *state, return loc::ConcreteInt(getBasicValueFactory().getValue(rightI)); } } - - // Delegate remaining pointer arithmetic to the StoreManager. - return state->getStateManager().getStoreManager().evalBinOp(op, lhs, - rhs, resultTy); + // Handle cases where 'lhs' is a region. + if (const MemRegion *region = lhs.getAsRegion()) { + rhs = cast(convertToArrayIndex(rhs)); + SVal index = UnknownVal(); + const MemRegion *superR = 0; + QualType elementType; + + if (const ElementRegion *elemReg = dyn_cast(region)) { + index = evalBinOpNN(state, BO_Add, elemReg->getIndex(), rhs, + getArrayIndexType()); + superR = elemReg->getSuperRegion(); + elementType = elemReg->getElementType(); + } + else if (isa(region)) { + superR = region; + index = rhs; + if (const PointerType *PT = resultTy->getAs()) { + elementType = PT->getPointeeType(); + } + else { + const ObjCObjectPointerType *OT = + resultTy->getAs(); + elementType = OT->getPointeeType(); + } + } + + if (NonLoc *indexV = dyn_cast(&index)) { + return loc::MemRegionVal(MemMgr.getElementRegion(elementType, *indexV, + superR, getContext())); + } + } + return UnknownVal(); } const llvm::APSInt *SimpleSValBuilder::getKnownValue(const GRState *state, diff --git a/test/Analysis/out-of-bounds.c b/test/Analysis/out-of-bounds.c index 598e165376..d8e4ad915a 100644 --- a/test/Analysis/out-of-bounds.c +++ b/test/Analysis/out-of-bounds.c @@ -44,7 +44,6 @@ void test1_ptr_ok(int x) { p[99] = 1; // no-warning } -// ** FIXME ** Doesn't work yet because we don't support pointer arithmetic. // Tests doing an out-of-bounds access before the start of an array using: // - indirect pointer to buffer, manipulated using simple pointer arithmetic // - constant integer index @@ -53,7 +52,7 @@ void test1_ptr_arith(int x) { int buf[100]; int *p = buf; p = p + 100; - p[0] = 1; // no-warning + p[0] = 1; // expected-warning{{Out of bound memory access}} } void test1_ptr_arith_ok(int x) { @@ -63,21 +62,18 @@ void test1_ptr_arith_ok(int x) { p[0] = 1; // no-warning } -// ** FIXME ** Doesn't work yet because we don't support pointer arithmetic. void test1_ptr_arith_bad(int x) { int buf[100]; int *p = buf; p = p + 99; - p[1] = 1; // no-warning + p[1] = 1; // expected-warning{{Out of bound memory access}} } -// ** FIXME ** we falsely emit a warning here because of our lack of -// handling of pointer arithmetic. void test1_ptr_arith_ok2(int x) { int buf[100]; int *p = buf; p = p + 99; - p[-1] = 1; // expected-warning{{Out of bound}} + p[-1] = 1; // no-warning } // Tests doing an out-of-bounds access before the start of an array using: