diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core')
| -rw-r--r-- | lib/StaticAnalyzer/Core/BugReporterVisitors.cpp | 37 | ||||
| -rw-r--r-- | lib/StaticAnalyzer/Core/CallEvent.cpp | 63 | ||||
| -rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 150 | ||||
| -rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineC.cpp | 2 | ||||
| -rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 43 | ||||
| -rw-r--r-- | lib/StaticAnalyzer/Core/IssueHash.cpp | 2 | ||||
| -rw-r--r-- | lib/StaticAnalyzer/Core/ProgramState.cpp | 5 | ||||
| -rw-r--r-- | lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp | 46 | ||||
| -rw-r--r-- | lib/StaticAnalyzer/Core/Store.cpp | 4 |
9 files changed, 201 insertions, 151 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index c87bc685d8b9..d4d33c1746ce 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -269,6 +269,8 @@ namespace { /// pointer dereference outside. class NoStoreFuncVisitor final : public BugReporterVisitor { const SubRegion *RegionOfInterest; + const SourceManager &SM; + const PrintingPolicy &PP; static constexpr const char *DiagnosticsMsg = "Returning without writing to '"; @@ -284,7 +286,10 @@ class NoStoreFuncVisitor final : public BugReporterVisitor { llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifyingCalculated; public: - NoStoreFuncVisitor(const SubRegion *R) : RegionOfInterest(R) {} + NoStoreFuncVisitor(const SubRegion *R) + : RegionOfInterest(R), + SM(R->getMemRegionManager()->getContext().getSourceManager()), + PP(R->getMemRegionManager()->getContext().getPrintingPolicy()) {} void Profile(llvm::FoldingSetNodeID &ID) const override { static int Tag = 0; @@ -307,8 +312,6 @@ public: CallEventRef<> Call = BRC.getStateManager().getCallEventManager().getCaller(SCtx, State); - const PrintingPolicy &PP = BRC.getASTContext().getPrintingPolicy(); - const SourceManager &SM = BRC.getSourceManager(); // Region of interest corresponds to an IVar, exiting a method // which could have written into that IVar, but did not. @@ -318,16 +321,14 @@ public: IvarR->getDecl()) && !isRegionOfInterestModifiedInFrame(N)) return notModifiedMemberDiagnostics( - Ctx, SM, PP, *CallExitLoc, Call, - MC->getReceiverSVal().getAsRegion()); + Ctx, *CallExitLoc, Call, MC->getReceiverSVal().getAsRegion()); if (const auto *CCall = dyn_cast<CXXConstructorCall>(Call)) { - const MemRegion *ThisRegion = CCall->getCXXThisVal().getAsRegion(); - if (RegionOfInterest->isSubRegionOf(ThisRegion) + const MemRegion *ThisR = CCall->getCXXThisVal().getAsRegion(); + if (RegionOfInterest->isSubRegionOf(ThisR) && !CCall->getDecl()->isImplicit() && !isRegionOfInterestModifiedInFrame(N)) - return notModifiedMemberDiagnostics(Ctx, SM, PP, *CallExitLoc, - CCall, ThisRegion); + return notModifiedMemberDiagnostics(Ctx, *CallExitLoc, Call, ThisR); } ArrayRef<ParmVarDecl *> parameters = getCallParameters(Call); @@ -344,7 +345,7 @@ public: return nullptr; return notModifiedParameterDiagnostics( - Ctx, SM, PP, *CallExitLoc, Call, PVD, R, IndirectionLevel); + Ctx, *CallExitLoc, Call, PVD, R, IndirectionLevel); } QualType PT = T->getPointeeType(); if (PT.isNull() || PT->isVoidType()) break; @@ -446,8 +447,6 @@ private: /// in a given function. std::shared_ptr<PathDiagnosticPiece> notModifiedMemberDiagnostics( const LocationContext *Ctx, - const SourceManager &SM, - const PrintingPolicy &PP, CallExitBegin &CallExitLoc, CallEventRef<> Call, const MemRegion *ArgRegion) { @@ -474,8 +473,6 @@ private: /// before we get to the super region of \c RegionOfInterest std::shared_ptr<PathDiagnosticPiece> notModifiedParameterDiagnostics(const LocationContext *Ctx, - const SourceManager &SM, - const PrintingPolicy &PP, CallExitBegin &CallExitLoc, CallEventRef<> Call, const ParmVarDecl *PVD, @@ -612,8 +609,7 @@ public: const ExplodedNode *N, const MemRegion *R, bool EnableNullFPSuppression, BugReport &BR, const SVal V) { - AnalyzerOptions &Options = N->getState()->getStateManager() - .getOwningEngine()->getAnalysisManager().options; + AnalyzerOptions &Options = N->getState()->getAnalysisManager().options; if (EnableNullFPSuppression && Options.shouldSuppressNullReturnPaths() && V.getAs<Loc>()) BR.addVisitor(llvm::make_unique<MacroNullReturnSuppressionVisitor>( @@ -740,9 +736,7 @@ public: RetVal = State->getSVal(*LValue); // See if the return value is NULL. If so, suppress the report. - SubEngine *Eng = State->getStateManager().getOwningEngine(); - assert(Eng && "Cannot file a bug report without an owning engine"); - AnalyzerOptions &Options = Eng->getAnalysisManager().options; + AnalyzerOptions &Options = State->getAnalysisManager().options; bool EnableNullFPSuppression = false; if (InEnableNullFPSuppression && Options.shouldSuppressNullReturnPaths()) @@ -1321,9 +1315,7 @@ SuppressInlineDefensiveChecksVisitor:: SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N) : V(Value) { // Check if the visitor is disabled. - SubEngine *Eng = N->getState()->getStateManager().getOwningEngine(); - assert(Eng && "Cannot file a bug report without an owning engine"); - AnalyzerOptions &Options = Eng->getAnalysisManager().options; + AnalyzerOptions &Options = N->getState()->getAnalysisManager().options; if (!Options.shouldSuppressInlinedDefensiveChecks()) IsSatisfied = true; @@ -1603,6 +1595,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, LVNode->getSVal(Inner).getAsRegion(); if (R) { + // Mark both the variable region and its contents as interesting. SVal V = LVState->getRawSVal(loc::MemRegionVal(R)); report.addVisitor( diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 8db7b06f186d..fe9260e32dd8 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -27,6 +27,7 @@ #include "clang/AST/Type.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/CrossTU/CrossTranslationUnit.h" #include "clang/Basic/IdentifierTable.h" @@ -166,6 +167,68 @@ bool CallEvent::isGlobalCFunction(StringRef FunctionName) const { return CheckerContext::isCLibraryFunction(FD, FunctionName); } +AnalysisDeclContext *CallEvent::getCalleeAnalysisDeclContext() const { + const Decl *D = getDecl(); + + // If the callee is completely unknown, we cannot construct the stack frame. + if (!D) + return nullptr; + + // FIXME: Skip virtual functions for now. There's no easy procedure to foresee + // the exact decl that should be used, especially when it's not a definition. + if (const Decl *RD = getRuntimeDefinition().getDecl()) + if (RD != D) + return nullptr; + + return LCtx->getAnalysisDeclContext()->getManager()->getContext(D); +} + +const StackFrameContext *CallEvent::getCalleeStackFrame() const { + AnalysisDeclContext *ADC = getCalleeAnalysisDeclContext(); + if (!ADC) + return nullptr; + + const Expr *E = getOriginExpr(); + if (!E) + return nullptr; + + // Recover CFG block via reverse lookup. + // TODO: If we were to keep CFG element information as part of the CallEvent + // instead of doing this reverse lookup, we would be able to build the stack + // frame for non-expression-based calls, and also we wouldn't need the reverse + // lookup. + CFGStmtMap *Map = LCtx->getAnalysisDeclContext()->getCFGStmtMap(); + const CFGBlock *B = Map->getBlock(E); + assert(B); + + // Also recover CFG index by scanning the CFG block. + unsigned Idx = 0, Sz = B->size(); + for (; Idx < Sz; ++Idx) + if (auto StmtElem = (*B)[Idx].getAs<CFGStmt>()) + if (StmtElem->getStmt() == E) + break; + assert(Idx < Sz); + + return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, Idx); +} + +const VarRegion *CallEvent::getParameterLocation(unsigned Index) const { + const StackFrameContext *SFC = getCalleeStackFrame(); + // We cannot construct a VarRegion without a stack frame. + if (!SFC) + return nullptr; + + const ParmVarDecl *PVD = parameters()[Index]; + const VarRegion *VR = + State->getStateManager().getRegionManager().getVarRegion(PVD, SFC); + + // This sanity check would fail if our parameter declaration doesn't + // correspond to the stack frame's function declaration. + assert(VR->getStackFrame() == SFC); + + return VR; +} + /// Returns true if a type is a pointer-to-const or reference-to-const /// with no further indirection. static bool isPointerToConst(QualType Ty) { diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 188316c096e3..2b4bdd754fdb 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -117,56 +117,42 @@ STATISTIC(NumTimesRetriedWithoutInlining, /// the construction context was present and contained references to these /// AST nodes. class ConstructedObjectKey { - typedef std::pair< - llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *>, - const LocationContext *> ConstructedObjectKeyImpl; + typedef std::pair<ConstructionContextItem, const LocationContext *> + ConstructedObjectKeyImpl; - ConstructedObjectKeyImpl Impl; + const ConstructedObjectKeyImpl Impl; const void *getAnyASTNodePtr() const { - if (const Stmt *S = getStmt()) + if (const Stmt *S = getItem().getStmtOrNull()) return S; else - return getCXXCtorInitializer(); + return getItem().getCXXCtorInitializer(); } public: - ConstructedObjectKey( - llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P, - const LocationContext *LC) - : Impl(P, LC) { - // This is the full list of statements that require additional actions when - // encountered. This list may be expanded when new actions are implemented. - assert(getCXXCtorInitializer() || isa<DeclStmt>(getStmt()) || - isa<CXXNewExpr>(getStmt()) || isa<CXXBindTemporaryExpr>(getStmt()) || - isa<MaterializeTemporaryExpr>(getStmt()) || - isa<CXXConstructExpr>(getStmt())); - } - - const Stmt *getStmt() const { - return Impl.first.dyn_cast<const Stmt *>(); - } + explicit ConstructedObjectKey(const ConstructionContextItem &Item, + const LocationContext *LC) + : Impl(Item, LC) {} - const CXXCtorInitializer *getCXXCtorInitializer() const { - return Impl.first.dyn_cast<const CXXCtorInitializer *>(); - } - - const LocationContext *getLocationContext() const { - return Impl.second; - } + const ConstructionContextItem &getItem() const { return Impl.first; } + const LocationContext *getLocationContext() const { return Impl.second; } void print(llvm::raw_ostream &OS, PrinterHelper *Helper, PrintingPolicy &PP) { - OS << '(' << getLocationContext() << ',' << getAnyASTNodePtr() << ") "; - if (const Stmt *S = getStmt()) { + OS << '(' << getLocationContext() << ',' << getAnyASTNodePtr() << ',' + << getItem().getKindAsString(); + if (getItem().getKind() == ConstructionContextItem::ArgumentKind) + OS << " #" << getItem().getIndex(); + OS << ") "; + if (const Stmt *S = getItem().getStmtOrNull()) { S->printPretty(OS, Helper, PP); } else { - const CXXCtorInitializer *I = getCXXCtorInitializer(); + const CXXCtorInitializer *I = getItem().getCXXCtorInitializer(); OS << I->getAnyMember()->getNameAsString(); } } void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddPointer(Impl.first.getOpaqueValue()); + ID.Add(Impl.first); ID.AddPointer(Impl.second); } @@ -184,15 +170,6 @@ typedef llvm::ImmutableMap<ConstructedObjectKey, SVal> REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction, ObjectsUnderConstructionMap) -// Additionally, track a set of destructors that correspond to elided -// constructors when copy elision occurs. -typedef std::pair<const CXXBindTemporaryExpr *, const LocationContext *> - ElidedDestructorItem; -typedef llvm::ImmutableSet<ElidedDestructorItem> - ElidedDestructorSet; -REGISTER_TRAIT_WITH_PROGRAMSTATE(ElidedDestructors, - ElidedDestructorSet) - //===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// @@ -449,31 +426,32 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, return State; } -ProgramStateRef ExprEngine::addObjectUnderConstruction( - ProgramStateRef State, - llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P, - const LocationContext *LC, SVal V) { - ConstructedObjectKey Key(P, LC->getStackFrame()); +ProgramStateRef +ExprEngine::addObjectUnderConstruction(ProgramStateRef State, + const ConstructionContextItem &Item, + const LocationContext *LC, SVal V) { + ConstructedObjectKey Key(Item, LC->getStackFrame()); // FIXME: Currently the state might already contain the marker due to // incorrect handling of temporaries bound to default parameters. assert(!State->get<ObjectsUnderConstruction>(Key) || - isa<CXXBindTemporaryExpr>(Key.getStmt())); + Key.getItem().getKind() == + ConstructionContextItem::TemporaryDestructorKind); return State->set<ObjectsUnderConstruction>(Key, V); } -Optional<SVal> ExprEngine::getObjectUnderConstruction( - ProgramStateRef State, - llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P, - const LocationContext *LC) { - ConstructedObjectKey Key(P, LC->getStackFrame()); +Optional<SVal> +ExprEngine::getObjectUnderConstruction(ProgramStateRef State, + const ConstructionContextItem &Item, + const LocationContext *LC) { + ConstructedObjectKey Key(Item, LC->getStackFrame()); return Optional<SVal>::create(State->get<ObjectsUnderConstruction>(Key)); } -ProgramStateRef ExprEngine::finishObjectConstruction( - ProgramStateRef State, - llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P, - const LocationContext *LC) { - ConstructedObjectKey Key(P, LC->getStackFrame()); +ProgramStateRef +ExprEngine::finishObjectConstruction(ProgramStateRef State, + const ConstructionContextItem &Item, + const LocationContext *LC) { + ConstructedObjectKey Key(Item, LC->getStackFrame()); assert(State->contains<ObjectsUnderConstruction>(Key)); return State->remove<ObjectsUnderConstruction>(Key); } @@ -481,25 +459,26 @@ ProgramStateRef ExprEngine::finishObjectConstruction( ProgramStateRef ExprEngine::elideDestructor(ProgramStateRef State, const CXXBindTemporaryExpr *BTE, const LocationContext *LC) { - ElidedDestructorItem I(BTE, LC); - assert(!State->contains<ElidedDestructors>(I)); - return State->add<ElidedDestructors>(I); + ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC); + // FIXME: Currently the state might already contain the marker due to + // incorrect handling of temporaries bound to default parameters. + return State->set<ObjectsUnderConstruction>(Key, UnknownVal()); } ProgramStateRef ExprEngine::cleanupElidedDestructor(ProgramStateRef State, const CXXBindTemporaryExpr *BTE, const LocationContext *LC) { - ElidedDestructorItem I(BTE, LC); - assert(State->contains<ElidedDestructors>(I)); - return State->remove<ElidedDestructors>(I); + ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC); + assert(State->contains<ObjectsUnderConstruction>(Key)); + return State->remove<ObjectsUnderConstruction>(Key); } bool ExprEngine::isDestructorElided(ProgramStateRef State, const CXXBindTemporaryExpr *BTE, const LocationContext *LC) { - ElidedDestructorItem I(BTE, LC); - return State->contains<ElidedDestructors>(I); + ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC); + return State->contains<ObjectsUnderConstruction>(Key); } bool ExprEngine::areAllObjectsFullyConstructed(ProgramStateRef State, @@ -512,10 +491,6 @@ bool ExprEngine::areAllObjectsFullyConstructed(ProgramStateRef State, if (I.first.getLocationContext() == LC) return false; - for (auto I: State->get<ElidedDestructors>()) - if (I.second == LC) - return false; - LC = LC->getParent(); } return true; @@ -560,14 +535,6 @@ static void printObjectsUnderConstructionForContext(raw_ostream &Out, Key.print(Out, nullptr, PP); Out << " : " << Value << NL; } - - for (auto I : State->get<ElidedDestructors>()) { - if (I.second != LC) - continue; - Out << '(' << I.second << ',' << (const void *)I.first << ") "; - I.first->printPretty(Out, nullptr, PP); - Out << " : (constructor elided)" << NL; - } } void ExprEngine::printState(raw_ostream &Out, ProgramStateRef State, @@ -2252,25 +2219,14 @@ void ExprEngine::processEndOfFunction(NodeBuilderContext& BC, for (auto I : State->get<ObjectsUnderConstruction>()) if (I.first.getLocationContext() == LC) { // The comment above only pardons us for not cleaning up a - // CXXBindTemporaryExpr. If any other statements are found here, + // temporary destructor. If any other statements are found here, // it must be a separate problem. - assert(isa<CXXBindTemporaryExpr>(I.first.getStmt())); + assert(I.first.getItem().getKind() == + ConstructionContextItem::TemporaryDestructorKind || + I.first.getItem().getKind() == + ConstructionContextItem::ElidedDestructorKind); State = State->remove<ObjectsUnderConstruction>(I.first); - // Also cleanup the elided destructor info. - ElidedDestructorItem Item( - cast<CXXBindTemporaryExpr>(I.first.getStmt()), - I.first.getLocationContext()); - State = State->remove<ElidedDestructors>(Item); } - - // Also suppress the assertion for elided destructors when temporary - // destructors are not provided at all by the CFG, because there's no - // good place to clean them up. - if (!AMgr.getAnalyzerOptions().includeTemporaryDtorsInCFG()) - for (auto I : State->get<ElidedDestructors>()) - if (I.second == LC) - State = State->remove<ElidedDestructors>(I); - LC = LC->getParent(); } if (State != Pred->getState()) { @@ -2338,7 +2294,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { // Evaluate the LHS of the case value. llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(getContext()); assert(V1.getBitWidth() == getContext().getIntWidth(CondE->getType())); - + // Get the RHS of the case, if it exists. llvm::APSInt V2; if (const Expr *E = Case->getRHS()) @@ -2538,12 +2494,12 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, ExplodedNodeSet CheckedSet; getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this); - ExplodedNodeSet EvalSet; - ValueDecl *Member = M->getMemberDecl(); + ExplodedNodeSet EvalSet; + ValueDecl *Member = M->getMemberDecl(); // Handle static member variables and enum constants accessed via // member syntax. - if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) { + if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) { for (const auto I : CheckedSet) VisitCommonDeclRefExpr(M, Member, I, EvalSet); } else { diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index c7b1a9ac82f0..61b7a290e42a 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -684,7 +684,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, // known to be false, 1 if the value is known to be true and a new symbol // when the assumption is unknown. nonloc::ConcreteInt Zero(getBasicVals().getValue(0, B->getType())); - X = evalBinOp(N->getState(), BO_NE, + X = evalBinOp(N->getState(), BO_NE, svalBuilder.evalCast(RHSVal, B->getType(), RHS->getType()), Zero, B->getType()); } diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index dc124fc3ff2d..4f1766a813c6 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -221,25 +221,42 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( // and construct directly into the final object. This call // also sets the CallOpts flags for us. SVal V; + // If the elided copy/move constructor is not supported, there's still + // benefit in trying to model the non-elided constructor. + // Stash our state before trying to elide, as it'll get overwritten. + ProgramStateRef PreElideState = State; + EvalCallOptions PreElideCallOpts = CallOpts; + std::tie(State, V) = prepareForObjectConstruction( CE, State, LCtx, TCC->getConstructionContextAfterElision(), CallOpts); - // Remember that we've elided the constructor. - State = addObjectUnderConstruction(State, CE, LCtx, V); + // FIXME: This definition of "copy elision has not failed" is unreliable. + // It doesn't indicate that the constructor will actually be inlined + // later; it is still up to evalCall() to decide. + if (!CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) { + // Remember that we've elided the constructor. + State = addObjectUnderConstruction(State, CE, LCtx, V); - // Remember that we've elided the destructor. - if (BTE) - State = elideDestructor(State, BTE, LCtx); + // Remember that we've elided the destructor. + if (BTE) + State = elideDestructor(State, BTE, LCtx); - // Instead of materialization, shamelessly return - // the final object destination. - if (MTE) - State = addObjectUnderConstruction(State, MTE, LCtx, V); + // Instead of materialization, shamelessly return + // the final object destination. + if (MTE) + State = addObjectUnderConstruction(State, MTE, LCtx, V); - return std::make_pair(State, V); + return std::make_pair(State, V); + } else { + // Copy elision failed. Revert the changes and proceed as if we have + // a simple temporary. + State = PreElideState; + CallOpts = PreElideCallOpts; + } + LLVM_FALLTHROUGH; } case ConstructionContext::SimpleTemporaryObjectKind: { - const auto *TCC = cast<SimpleTemporaryObjectConstructionContext>(CC); + const auto *TCC = cast<TemporaryObjectConstructionContext>(CC); const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr(); const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr(); SVal V = UnknownVal(); @@ -274,6 +291,10 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( CallOpts.IsTemporaryCtorOrDtor = true; return std::make_pair(State, V); } + case ConstructionContext::ArgumentKind: { + // Function argument constructors. Not implemented yet. + break; + } } } // If we couldn't find an existing region to construct into, assume we're diff --git a/lib/StaticAnalyzer/Core/IssueHash.cpp b/lib/StaticAnalyzer/Core/IssueHash.cpp index 274ebe7a941b..6c55c61dd399 100644 --- a/lib/StaticAnalyzer/Core/IssueHash.cpp +++ b/lib/StaticAnalyzer/Core/IssueHash.cpp @@ -26,7 +26,7 @@ using namespace clang; -// Get a string representation of the parts of the signature that can be +// Get a string representation of the parts of the signature that can be // overloaded on. static std::string GetSignature(const FunctionDecl *Target) { if (!Target) diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index 2b401607293b..94e2e00d8bbc 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/Analysis/CFG.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" @@ -494,6 +495,10 @@ void ProgramState::dumpTaint() const { printTaint(llvm::errs()); } +AnalysisManager& ProgramState::getAnalysisManager() const { + return stateMgr->getOwningEngine()->getAnalysisManager(); +} + //===----------------------------------------------------------------------===// // Generic Data Map. //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index beae0dfae289..62c54fc956a9 100644 --- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -440,7 +440,7 @@ static bool shouldRearrange(ProgramStateRef State, BinaryOperator::Opcode Op, SymbolRef Sym, llvm::APSInt Int, QualType Ty) { return Sym->getType() == Ty && (!BinaryOperator::isComparisonOp(Op) || - (isWithinConstantOverflowBounds(Sym, State) && + (isWithinConstantOverflowBounds(Sym, State) && isWithinConstantOverflowBounds(Int))); } @@ -1236,11 +1236,21 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { return Sym == Val.getAsSymbol(); } + SVal cache(SymbolRef Sym, SVal V) { + Cached[Sym] = V; + return V; + } + + SVal skip(SymbolRef Sym) { + return cache(Sym, SVB.makeSymbolVal(Sym)); + } + public: Simplifier(ProgramStateRef State) : State(State), SVB(State->getStateManager().getSValBuilder()) {} SVal VisitSymbolData(const SymbolData *S) { + // No cache here. if (const llvm::APSInt *I = SVB.getKnownValue(State, SVB.makeSymbolVal(S))) return Loc::isLocType(S->getType()) ? (SVal)SVB.makeIntLocVal(*I) @@ -1257,11 +1267,9 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { return I->second; SVal LHS = Visit(S->getLHS()); - if (isUnchanged(S->getLHS(), LHS)) { - SVal V = SVB.makeSymbolVal(S); - Cached[S] = V; - return V; - } + if (isUnchanged(S->getLHS(), LHS)) + return skip(S); + SVal RHS; // By looking at the APSInt in the right-hand side of S, we cannot // figure out if it should be treated as a Loc or as a NonLoc. @@ -1281,9 +1289,8 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { RHS = SVB.makeIntVal(S->getRHS()); } - SVal V = SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType()); - Cached[S] = V; - return V; + return cache( + S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType())); } SVal VisitSymSymExpr(const SymSymExpr *S) { @@ -1291,16 +1298,21 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { if (I != Cached.end()) return I->second; + // For now don't try to simplify mixed Loc/NonLoc expressions + // because they often appear from LocAsInteger operations + // and we don't know how to combine a LocAsInteger + // with a concrete value. + if (Loc::isLocType(S->getLHS()->getType()) != + Loc::isLocType(S->getRHS()->getType())) + return skip(S); + SVal LHS = Visit(S->getLHS()); SVal RHS = Visit(S->getRHS()); - if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS)) { - SVal V = SVB.makeSymbolVal(S); - Cached[S] = V; - return V; - } - SVal V = SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType()); - Cached[S] = V; - return V; + if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS)) + return skip(S); + + return cache( + S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType())); } SVal VisitSymExpr(SymbolRef S) { return nonloc::SymbolVal(S); } diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp index 5ab5c082269b..94188a9ef698 100644 --- a/lib/StaticAnalyzer/Core/Store.cpp +++ b/lib/StaticAnalyzer/Core/Store.cpp @@ -448,10 +448,10 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, // value. See also the similar FIXME in getLValueFieldOrIvar(). if (Base.isUnknownOrUndef() || Base.getAs<loc::ConcreteInt>()) return Base; - + if (Base.getAs<loc::GotoLabel>()) return UnknownVal(); - + const SubRegion *BaseRegion = Base.castAs<loc::MemRegionVal>().getRegionAs<SubRegion>(); |
