diff options
-rw-r--r-- | include/clang/Analysis/PathSensitive/AnalysisContext.h | 2 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/MemRegion.h | 28 | ||||
-rw-r--r-- | lib/Analysis/AnalysisContext.cpp | 13 | ||||
-rw-r--r-- | lib/Analysis/MemRegion.cpp | 31 | ||||
-rw-r--r-- | lib/Analysis/RegionStore.cpp | 5 | ||||
-rw-r--r-- | lib/Analysis/Store.cpp | 1 | ||||
-rw-r--r-- | test/Analysis/misc-ps-region-store.m | 39 |
7 files changed, 102 insertions, 17 deletions
diff --git a/include/clang/Analysis/PathSensitive/AnalysisContext.h b/include/clang/Analysis/PathSensitive/AnalysisContext.h index 0a6646e550..abc33b7784 100644 --- a/include/clang/Analysis/PathSensitive/AnalysisContext.h +++ b/include/clang/Analysis/PathSensitive/AnalysisContext.h @@ -120,6 +120,8 @@ public: } const StackFrameContext *getCurrentStackFrame() const; + const StackFrameContext * + getStackFrameForDeclContext(const DeclContext *DC) const; virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index efe4b9bb96..45dab1ec84 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -53,6 +53,7 @@ public: StackLocalsSpaceRegionKind, StackArgumentsSpaceRegionKind, HeapSpaceRegionKind, + UnknownSpaceRegionKind, GlobalsSpaceRegionKind, END_MEMSPACES = GlobalsSpaceRegionKind, // Untyped regions. @@ -171,6 +172,16 @@ public: } }; +class UnknownSpaceRegion : public MemSpaceRegion { + friend class MemRegionManager; + UnknownSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == UnknownSpaceRegionKind; + } +}; + class StackSpaceRegion : public MemSpaceRegion { private: const StackFrameContext *SFC; @@ -757,16 +768,23 @@ class MemRegionManager { llvm::FoldingSet<MemRegion> Regions; GlobalsSpaceRegion *globals; - StackLocalsSpaceRegion *stackLocals; - StackArgumentsSpaceRegion *stackArguments; + + const StackFrameContext *cachedStackLocalsFrame; + StackLocalsSpaceRegion *cachedStackLocalsRegion; + + const StackFrameContext *cachedStackArgumentsFrame; + StackArgumentsSpaceRegion *cachedStackArgumentsRegion; + HeapSpaceRegion *heap; - MemSpaceRegion *unknown; + UnknownSpaceRegion *unknown; MemSpaceRegion *code; public: MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a) - : C(c), A(a), globals(0), stackLocals(0), stackArguments(0), heap(0), - unknown(0), code(0) {} + : C(c), A(a), globals(0), + cachedStackLocalsFrame(0), cachedStackLocalsRegion(0), + cachedStackArgumentsFrame(0), cachedStackArgumentsRegion(0), + heap(0), unknown(0), code(0) {} ~MemRegionManager(); diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 113587f60e..3a6cf42a3d 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -179,6 +179,19 @@ const StackFrameContext *LocationContext::getCurrentStackFrame() const { return NULL; } +const StackFrameContext * +LocationContext::getStackFrameForDeclContext(const DeclContext *DC) const { + const LocationContext *LC = this; + while (LC) { + if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) { + if (cast<DeclContext>(SFC->getDecl()) == DC) + return SFC; + } + LC = LC->getParent(); + } + return NULL; +} + //===----------------------------------------------------------------------===// // Lazily generated map to query the external variables referenced by a Block. //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 3bf3e5b28a..da45c4dfee 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -381,13 +381,22 @@ const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) { } const StackLocalsSpaceRegion* -MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) { - return LazyAllocate(stackLocals, STC); +MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) { + assert(STC); + if (STC == cachedStackLocalsFrame) + return cachedStackLocalsRegion; + cachedStackLocalsFrame = STC; + return LazyAllocate(cachedStackLocalsRegion, STC); } const StackArgumentsSpaceRegion * MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) { - return LazyAllocate(stackArguments, STC); + assert(STC); + if (STC == cachedStackArgumentsFrame) + return cachedStackArgumentsRegion; + + cachedStackArgumentsFrame = STC; + return LazyAllocate(cachedStackArgumentsRegion, STC); } const GlobalsSpaceRegion *MemRegionManager::getGlobalsRegion() { @@ -418,15 +427,19 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, const LocationContext *LC) { const MemRegion *sReg = 0; - if (D->hasLocalStorage()) { + if (D->hasLocalStorage()) { // FIXME: Once we implement scope handling, we will need to properly lookup // 'D' to the proper LocationContext. - const StackFrameContext *STC = LC->getCurrentStackFrame(); + const DeclContext *DC = D->getDeclContext(); + const StackFrameContext *STC = LC->getStackFrameForDeclContext(DC); - assert(STC); - sReg = isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) - ? static_cast<const MemRegion*>(getStackArgumentsRegion(STC)) - : static_cast<const MemRegion*>(getStackLocalsRegion(STC)); + if (!STC) + sReg = getUnknownRegion(); + else { + sReg = isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) + ? static_cast<const MemRegion*>(getStackArgumentsRegion(STC)) + : static_cast<const MemRegion*>(getStackLocalsRegion(STC)); + } } else { sReg = getGlobalsRegion(); diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index c718f1fbba..b5eeb1ea11 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -728,6 +728,7 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, case MemRegion::StackArgumentsSpaceRegionKind: case MemRegion::HeapSpaceRegionKind: case MemRegion::GlobalsSpaceRegionKind: + case MemRegion::UnknownSpaceRegionKind: assert(0 && "Cannot index into a MemSpace"); return UnknownVal(); @@ -881,6 +882,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, case MemRegion::StackArgumentsSpaceRegionKind: case MemRegion::HeapSpaceRegionKind: case MemRegion::GlobalsSpaceRegionKind: + case MemRegion::UnknownSpaceRegionKind: assert(0 && "Cannot perform pointer arithmetic on a MemSpace"); return UnknownVal(); } @@ -1292,7 +1294,8 @@ SVal RegionStoreManager::RetrieveVar(const GRState *state, // Lazily derive a value for the VarRegion. const VarDecl *VD = R->getDecl(); - if (R->hasGlobalsOrParametersStorage()) + if (R->hasGlobalsOrParametersStorage() || + isa<UnknownSpaceRegion>(R->getMemorySpace())) return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType()); return UndefinedVal(); diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index be4ce2d57c..e6ff6e5af4 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -81,6 +81,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: case MemRegion::HeapSpaceRegionKind: + case MemRegion::UnknownSpaceRegionKind: case MemRegion::GlobalsSpaceRegionKind: { assert(0 && "Invalid region cast"); break; diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m index ee2043c214..f030484592 100644 --- a/test/Analysis/misc-ps-region-store.m +++ b/test/Analysis/misc-ps-region-store.m @@ -1,5 +1,5 @@ -// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s -// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks %s +// RUN: clang-cc -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s +// RUN: clang-cc -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s typedef struct objc_selector *SEL; typedef signed char BOOL; @@ -583,3 +583,38 @@ int blocks_2(int *p, int z) { return z; } +//===----------------------------------------------------------------------===// +// <rdar://problem/7462324> - Test that variables passed using __blocks +// are not treated as being uninitialized. +//===----------------------------------------------------------------------===// + +typedef void (^RDar_7462324_Callback)(id obj); + +@interface RDar7462324 +- (void) foo:(id)target; +- (void) foo_positive:(id)target; + +@end + +@implementation RDar7462324 +- (void) foo:(id)target { + __block RDar_7462324_Callback builder = ((void*) 0); + builder = ^(id object) { + if (object) { + builder(self); // no-warning + } + }; + builder(target); +} +- (void) foo_positive:(id)target { + __block RDar_7462324_Callback builder = ((void*) 0); + builder = ^(id object) { + id x; + if (object) { + builder(x); // expected-warning{{Pass-by-value argument in function call is undefined}} + } + }; + builder(target); +} +@end + |