diff options
author | Ted Kremenek <kremenek@apple.com> | 2009-01-22 20:27:48 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2009-01-22 20:27:48 +0000 |
commit | 92d48a71f551093efbbbd53f402c4257cf91f8d3 (patch) | |
tree | 565a0f0e2b8b0c95fe6b9104a8ce2db253fcfa38 /clang | |
parent | 483e12e09e0d9016a754be6c45e967435f8d31e0 (diff) | |
download | bcm5719-llvm-92d48a71f551093efbbbd53f402c4257cf91f8d3.tar.gz bcm5719-llvm-92d48a71f551093efbbbd53f402c4257cf91f8d3.zip |
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.
llvm-svn: 62781
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Analysis/RegionStore.cpp | 87 | ||||
-rw-r--r-- | clang/test/Analysis/array-struct.c | 5 | ||||
-rw-r--r-- | clang/test/Analysis/outofbound.c | 2 |
3 files changed, 54 insertions, 40 deletions
diff --git a/clang/lib/Analysis/RegionStore.cpp b/clang/lib/Analysis/RegionStore.cpp index 5a13a1dbc25..6f0ec1d0b73 100644 --- a/clang/lib/Analysis/RegionStore.cpp +++ b/clang/lib/Analysis/RegionStore.cpp @@ -327,49 +327,62 @@ SVal RegionStoreManager::getLValueElement(const GRState* St, if (Base.isUnknownOrUndef() || isa<loc::SymbolVal>(Base)) return Base; - loc::MemRegionVal& BaseL = cast<loc::MemRegionVal>(Base); - - // Pointer of any type can be cast and used as array base. We do not support - // that case yet. - if (!isa<ElementRegion>(BaseL.getRegion())) { - // Record what we have seen in real code. - assert(isa<FieldRegion>(BaseL.getRegion())); + // Only handle integer offsets... for now. + if (!isa<nonloc::ConcreteInt>(Offset)) return UnknownVal(); - } - - // We expect BaseR is an ElementRegion, not a base VarRegion. - - const ElementRegion* ElemR = cast<ElementRegion>(BaseL.getRegion()); - - SVal Idx = ElemR->getIndex(); - nonloc::ConcreteInt *CI1, *CI2; + const TypedRegion *BaseRegion = + cast<TypedRegion>(cast<loc::MemRegionVal>(Base).getRegion()); - // Only handle integer indices for now. - if ((CI1 = dyn_cast<nonloc::ConcreteInt>(&Idx)) && - (CI2 = dyn_cast<nonloc::ConcreteInt>(&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<nonloc::ConcreteInt>(&SignedInt); - } + // Pointer of any type can be cast and used as array base. + const ElementRegion *ElemR = dyn_cast<ElementRegion>(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<AllocaRegion>. + // + return loc::MemRegionVal(MRMgr.getElementRegion(Offset, BaseRegion)); + } + + SVal BaseIdx = ElemR->getIndex(); + + if (!isa<nonloc::ConcreteInt>(BaseIdx)) + return UnknownVal(); + + const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue(); + const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(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/clang/test/Analysis/array-struct.c b/clang/test/Analysis/array-struct.c index 1d5e9448e92..4257220f9bd 100644 --- a/clang/test/Analysis/array-struct.c +++ b/clang/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/clang/test/Analysis/outofbound.c b/clang/test/Analysis/outofbound.c index ab9c0cfa4c8..b0c2db43862 100644 --- a/clang/test/Analysis/outofbound.c +++ b/clang/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.}} } |