From: Ted Kremenek Date: Thu, 22 Jan 2009 20:27:48 +0000 (+0000) Subject: Fix RegionStore::getLValueElement() to handle the case when the base region is not... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a7ac9444b4b82de868fac9710a56807898a90b02;p=clang Fix RegionStore::getLValueElement() to handle the case when the base region is not an ElementRegion (also do some cleanups of its core logic). This gets array-struct.c to work with RegionStore. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62781 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 5a13a1dbc2..6f0ec1d0b7 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -327,49 +327,62 @@ SVal RegionStoreManager::getLValueElement(const GRState* St, if (Base.isUnknownOrUndef() || isa(Base)) return Base; - loc::MemRegionVal& BaseL = cast(Base); - - // Pointer of any type can be cast and used as array base. We do not support - // that case yet. - if (!isa(BaseL.getRegion())) { - // Record what we have seen in real code. - assert(isa(BaseL.getRegion())); + // Only handle integer offsets... for now. + if (!isa(Offset)) return UnknownVal(); - } - - // We expect BaseR is an ElementRegion, not a base VarRegion. - - const ElementRegion* ElemR = cast(BaseL.getRegion()); - - SVal Idx = ElemR->getIndex(); - nonloc::ConcreteInt *CI1, *CI2; + const TypedRegion *BaseRegion = + cast(cast(Base).getRegion()); - // Only handle integer indices for now. - if ((CI1 = dyn_cast(&Idx)) && - (CI2 = dyn_cast(&Offset))) { - - // Temporary SVal to hold a potential signed and extended APSInt. - SVal SignedInt; - - // Index might be unsigned. We have to convert it to signed. It might also - // be less wide than the size. We have to extend it. - if (CI2->getValue().isUnsigned() || - CI2->getValue().getBitWidth() < CI1->getValue().getBitWidth()) { - llvm::APSInt SI = CI2->getValue(); - if (CI2->getValue().getBitWidth() < CI1->getValue().getBitWidth()) - SI.extend(CI1->getValue().getBitWidth()); - SI.setIsSigned(true); - SignedInt = nonloc::ConcreteInt(getBasicVals().getValue(SI)); - CI2 = cast(&SignedInt); - } + // Pointer of any type can be cast and used as array base. + const ElementRegion *ElemR = dyn_cast(BaseRegion); + + if (!ElemR) { + // + // If the base region is not an ElementRegion, create one. + // This can happen in the following example: + // + // char *p = __builtin_alloc(10); + // p[1] = 8; + // + // Observe that 'p' binds to an AnonTypedRegion. + // + return loc::MemRegionVal(MRMgr.getElementRegion(Offset, BaseRegion)); + } + + SVal BaseIdx = ElemR->getIndex(); + + if (!isa(BaseIdx)) + return UnknownVal(); + + const llvm::APSInt& BaseIdxI = cast(BaseIdx).getValue(); + const llvm::APSInt& OffI = cast(Offset).getValue(); + assert(BaseIdxI.isSigned()); + + // FIXME: This appears to be the assumption of this code. We should review + // whether or not BaseIdxI.getBitWidth() < OffI.getBitWidth(). If it + // can't we need to put a comment here. If it can, we should handle it. + assert(BaseIdxI.getBitWidth() >= OffI.getBitWidth()); - SVal NewIdx = CI1->EvalBinOp(getBasicVals(), BinaryOperator::Add, *CI2); - return loc::MemRegionVal(MRMgr.getElementRegion(NewIdx, - ElemR->getArrayRegion())); + const TypedRegion *ArrayR = ElemR->getArrayRegion(); + SVal NewIdx; + + if (OffI.isUnsigned() || OffI.getBitWidth() < BaseIdxI.getBitWidth()) { + // 'Offset' might be unsigned. We have to convert it to signed and + // possibly extend it. + llvm::APSInt Tmp = OffI; + + if (OffI.getBitWidth() < BaseIdxI.getBitWidth()) + Tmp.extend(BaseIdxI.getBitWidth()); + + Tmp.setIsSigned(true); + Tmp += BaseIdxI; // Compute the new offset. + NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(Tmp)); } + else + NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI)); - return UnknownVal(); + return loc::MemRegionVal(MRMgr.getElementRegion(NewIdx, ArrayR)); } SVal RegionStoreManager::getSizeInElements(const GRState* St, diff --git a/test/Analysis/array-struct.c b/test/Analysis/array-struct.c index 1d5e9448e9..4257220f9b 100644 --- a/test/Analysis/array-struct.c +++ b/test/Analysis/array-struct.c @@ -1,5 +1,6 @@ -// RUN: clang -analyze -checker-simple -verify %s -// DISABLE: clang -analyze -checker-simple -analyzer-store-region -verify %s +// RUN: clang -analyze -checker-simple -analyzer-store-basic -verify %s && +// RUN: clang -analyze -checker-cfref -analyzer-store-basic -verify %s && +// RUN: clang -analyze -checker-cfref -analyzer-store-region -verify %s struct s { int data; diff --git a/test/Analysis/outofbound.c b/test/Analysis/outofbound.c index ab9c0cfa4c..b0c2db4386 100644 --- a/test/Analysis/outofbound.c +++ b/test/Analysis/outofbound.c @@ -2,5 +2,5 @@ char f1() { char* s = "abcd"; - return s[5]; // expected-warning{{Load or store into an out-of-bound memory position.}} + return s[6]; // expected-warning{{Load or store into an out-of-bound memory position.}} }