diff options
author | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
commit | c72c57c9e9b69944e3e009cd5e209634839581d3 (patch) | |
tree | 4fc2f184c499d106f29a386c452b49e5197bf63d /lib/StaticAnalyzer/Core/CallEvent.cpp | |
parent | 5b20025c30d23d521e12c1f33ec8fa6b821952cd (diff) | |
download | FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.zip FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.tar.gz |
Vendor import of clang trunk r178860:
http://llvm.org/svn/llvm-project/cfe/trunk@178860
Diffstat (limited to 'lib/StaticAnalyzer/Core/CallEvent.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/CallEvent.cpp | 129 |
1 files changed, 61 insertions, 68 deletions
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index c5cb317..45b2e21 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -14,11 +14,12 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/Analysis/ProgramPoint.h" #include "clang/AST/ParentMap.h" +#include "clang/Analysis/ProgramPoint.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace ento; @@ -124,7 +125,7 @@ static bool isPointerToConst(QualType Ty) { // Try to retrieve the function declaration and find the function parameter // types which are pointers/references to a non-pointer const. // We will not invalidate the corresponding argument regions. -static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, +static void findPtrToConstParams(llvm::SmallSet<unsigned, 4> &PreserveArgs, const CallEvent &Call) { unsigned Idx = 0; for (CallEvent::param_type_iterator I = Call.param_type_begin(), @@ -136,69 +137,35 @@ static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, } ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, - ProgramStateRef Orig) const { + ProgramStateRef Orig) const { ProgramStateRef Result = (Orig ? Orig : getState()); - SmallVector<const MemRegion *, 8> RegionsToInvalidate; - getExtraInvalidatedRegions(RegionsToInvalidate); + SmallVector<SVal, 8> ConstValues; + SmallVector<SVal, 8> ValuesToInvalidate; + + getExtraInvalidatedValues(ValuesToInvalidate); // Indexes of arguments whose values will be preserved by the call. - llvm::SmallSet<unsigned, 1> PreserveArgs; + llvm::SmallSet<unsigned, 4> PreserveArgs; if (!argumentsMayEscape()) findPtrToConstParams(PreserveArgs, *this); for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) { + // Mark this region for invalidation. We batch invalidate regions + // below for efficiency. if (PreserveArgs.count(Idx)) - continue; - - SVal V = getArgSVal(Idx); - - // If we are passing a location wrapped as an integer, unwrap it and - // invalidate the values referred by the location. - if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V)) - V = Wrapped->getLoc(); - else if (!isa<Loc>(V)) - continue; - - if (const MemRegion *R = V.getAsRegion()) { - // Invalidate the value of the variable passed by reference. - - // Are we dealing with an ElementRegion? If the element type is - // a basic integer type (e.g., char, int) and the underlying region - // is a variable region then strip off the ElementRegion. - // FIXME: We really need to think about this for the general case - // as sometimes we are reasoning about arrays and other times - // about (char*), etc., is just a form of passing raw bytes. - // e.g., void *p = alloca(); foo((char*)p); - if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { - // Checking for 'integral type' is probably too promiscuous, but - // we'll leave it in for now until we have a systematic way of - // handling all of these cases. Eventually we need to come up - // with an interface to StoreManager so that this logic can be - // appropriately delegated to the respective StoreManagers while - // still allowing us to do checker-specific logic (e.g., - // invalidating reference counts), probably via callbacks. - if (ER->getElementType()->isIntegralOrEnumerationType()) { - const MemRegion *superReg = ER->getSuperRegion(); - if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) || - isa<ObjCIvarRegion>(superReg)) - R = cast<TypedRegion>(superReg); - } - // FIXME: What about layers of ElementRegions? - } - - // Mark this region for invalidation. We batch invalidate regions - // below for efficiency. - RegionsToInvalidate.push_back(R); - } + ConstValues.push_back(getArgSVal(Idx)); + else + ValuesToInvalidate.push_back(getArgSVal(Idx)); } // Invalidate designated regions using the batch invalidation API. // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate // global variables. - return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(), + return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(), BlockCount, getLocationContext(), - /*Symbols=*/0, this); + /*CausedByPointerEscape*/ true, + /*Symbols=*/0, this, ConstValues); } ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, @@ -268,7 +235,6 @@ bool CallEvent::isCallStmt(const Stmt *S) { || isa<CXXNewExpr>(S); } -/// \brief Returns the result type, adjusted for references. QualType CallEvent::getDeclaredResultType(const Decl *D) { assert(D); if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) @@ -405,9 +371,8 @@ const FunctionDecl *CXXInstanceCall::getDecl() const { return getSVal(CE->getCallee()).getAsFunctionDecl(); } -void CXXInstanceCall::getExtraInvalidatedRegions(RegionList &Regions) const { - if (const MemRegion *R = getCXXThisVal().getAsRegion()) - Regions.push_back(R); +void CXXInstanceCall::getExtraInvalidatedValues(ValueList &Values) const { + Values.push_back(getCXXThisVal()); } SVal CXXInstanceCall::getCXXThisVal() const { @@ -417,7 +382,7 @@ SVal CXXInstanceCall::getCXXThisVal() const { return UnknownVal(); SVal ThisVal = getSVal(Base); - assert(ThisVal.isUnknownOrUndef() || isa<Loc>(ThisVal)); + assert(ThisVal.isUnknownOrUndef() || ThisVal.getAs<Loc>()); return ThisVal; } @@ -560,10 +525,10 @@ CallEvent::param_iterator BlockCall::param_end() const { return D->param_end(); } -void BlockCall::getExtraInvalidatedRegions(RegionList &Regions) const { +void BlockCall::getExtraInvalidatedValues(ValueList &Values) const { // FIXME: This also needs to invalidate captured globals. if (const MemRegion *R = getBlockRegion()) - Regions.push_back(R); + Values.push_back(loc::MemRegionVal(R)); } void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx, @@ -581,9 +546,9 @@ SVal CXXConstructorCall::getCXXThisVal() const { return UnknownVal(); } -void CXXConstructorCall::getExtraInvalidatedRegions(RegionList &Regions) const { +void CXXConstructorCall::getExtraInvalidatedValues(ValueList &Values) const { if (Data) - Regions.push_back(static_cast<const MemRegion *>(Data)); + Values.push_back(loc::MemRegionVal(static_cast<const MemRegion *>(Data))); } void CXXConstructorCall::getInitialStackFrameContents( @@ -635,9 +600,8 @@ CallEvent::param_iterator ObjCMethodCall::param_end() const { } void -ObjCMethodCall::getExtraInvalidatedRegions(RegionList &Regions) const { - if (const MemRegion *R = getReceiverSVal().getAsRegion()) - Regions.push_back(R); +ObjCMethodCall::getExtraInvalidatedValues(ValueList &Values) const { + Values.push_back(getReceiverSVal()); } SVal ObjCMethodCall::getSelfSVal() const { @@ -834,7 +798,34 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { // Lookup the method implementation. if (ReceiverT) if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) { - const ObjCMethodDecl *MD = IDecl->lookupPrivateMethod(Sel); + // Repeatedly calling lookupPrivateMethod() is expensive, especially + // when in many cases it returns null. We cache the results so + // that repeated queries on the same ObjCIntefaceDecl and Selector + // don't incur the same cost. On some test cases, we can see the + // same query being issued thousands of times. + // + // NOTE: This cache is essentially a "global" variable, but it + // only gets lazily created when we get here. The value of the + // cache probably comes from it being global across ExprEngines, + // where the same queries may get issued. If we are worried about + // concurrency, or possibly loading/unloading ASTs, etc., we may + // need to revisit this someday. In terms of memory, this table + // stays around until clang quits, which also may be bad if we + // need to release memory. + typedef std::pair<const ObjCInterfaceDecl*, Selector> + PrivateMethodKey; + typedef llvm::DenseMap<PrivateMethodKey, + Optional<const ObjCMethodDecl *> > + PrivateMethodCache; + + static PrivateMethodCache PMC; + Optional<const ObjCMethodDecl *> &Val = PMC[std::make_pair(IDecl, Sel)]; + + // Query lookupPrivateMethod() if the cache does not hit. + if (!Val.hasValue()) + Val = IDecl->lookupPrivateMethod(Sel); + + const ObjCMethodDecl *MD = Val.getValue(); if (CanBeSubClassed) return RuntimeDefinition(MD, Receiver); else @@ -931,8 +922,9 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, // destructors, though this could change in the future. const CFGBlock *B = CalleeCtx->getCallSiteBlock(); CFGElement E = (*B)[CalleeCtx->getIndex()]; - assert(isa<CFGImplicitDtor>(E) && "All other CFG elements should have exprs"); - assert(!isa<CFGTemporaryDtor>(E) && "We don't handle temporaries yet"); + assert(E.getAs<CFGImplicitDtor>() && + "All other CFG elements should have exprs"); + assert(!E.getAs<CFGTemporaryDtor>() && "We don't handle temporaries yet"); SValBuilder &SVB = State->getStateManager().getSValBuilder(); const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CalleeCtx->getDecl()); @@ -940,11 +932,12 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, SVal ThisVal = State->getSVal(ThisPtr); const Stmt *Trigger; - if (const CFGAutomaticObjDtor *AutoDtor = dyn_cast<CFGAutomaticObjDtor>(&E)) + if (Optional<CFGAutomaticObjDtor> AutoDtor = E.getAs<CFGAutomaticObjDtor>()) Trigger = AutoDtor->getTriggerStmt(); else Trigger = Dtor->getBody(); return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(), - isa<CFGBaseDtor>(E), State, CallerCtx); + E.getAs<CFGBaseDtor>().hasValue(), State, + CallerCtx); } |