diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/CallEvent.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/CallEvent.cpp | 162 |
1 files changed, 123 insertions, 39 deletions
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index fe9260e32dd8b..0e7f31502e81a 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -169,18 +169,27 @@ bool CallEvent::isGlobalCFunction(StringRef FunctionName) const { 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; + // TODO: For now we skip functions without definitions, even if we have + // our own getDecl(), because it's hard to find out which re-declaration + // is going to be used, and usually clients don't really care about this + // situation because there's a loss of precision anyway because we cannot + // inline the call. + RuntimeDefinition RD = getRuntimeDefinition(); + if (!RD.getDecl()) + return nullptr; + + AnalysisDeclContext *ADC = + LCtx->getAnalysisDeclContext()->getManager()->getContext(D); + + // TODO: For now we skip virtual functions, because this also rises + // the problem of which decl to use, but now it's across different classes. + if (RD.mayHaveOtherDefinitions() || RD.getDecl() != ADC->getDecl()) + return nullptr; - return LCtx->getAnalysisDeclContext()->getManager()->getContext(D); + return ADC; } const StackFrameContext *CallEvent::getCalleeStackFrame() const { @@ -218,7 +227,24 @@ const VarRegion *CallEvent::getParameterLocation(unsigned Index) const { if (!SFC) return nullptr; - const ParmVarDecl *PVD = parameters()[Index]; + // Retrieve parameters of the definition, which are different from + // CallEvent's parameters() because getDecl() isn't necessarily + // the definition. SFC contains the definition that would be used + // during analysis. + const Decl *D = SFC->getDecl(); + + // TODO: Refactor into a virtual method of CallEvent, like parameters(). + const ParmVarDecl *PVD = nullptr; + if (const auto *FD = dyn_cast<FunctionDecl>(D)) + PVD = FD->parameters()[Index]; + else if (const auto *BD = dyn_cast<BlockDecl>(D)) + PVD = BD->parameters()[Index]; + else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + PVD = MD->parameters()[Index]; + else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) + PVD = CD->parameters()[Index]; + assert(PVD && "Unexpected Decl kind!"); + const VarRegion *VR = State->getStateManager().getRegionManager().getVarRegion(PVD, SFC); @@ -285,6 +311,20 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount, // TODO: Factor this out + handle the lower level const pointers. ValuesToInvalidate.push_back(getArgSVal(Idx)); + + // If a function accepts an object by argument (which would of course be a + // temporary that isn't lifetime-extended), invalidate the object itself, + // not only other objects reachable from it. This is necessary because the + // destructor has access to the temporary object after the call. + // TODO: Support placement arguments once we start + // constructing them directly. + // TODO: This is unnecessary when there's no destructor, but that's + // currently hard to figure out. + if (getKind() != CE_CXXAllocator) + if (isArgumentConstructedDirectly(Idx)) + if (auto AdjIdx = getAdjustedParameterIndex(Idx)) + if (const VarRegion *VR = getParameterLocation(*AdjIdx)) + ValuesToInvalidate.push_back(loc::MemRegionVal(VR)); } // Invalidate designated regions using the batch invalidation API. @@ -319,11 +359,41 @@ bool CallEvent::isCalled(const CallDescription &CD) const { return false; if (!CD.IsLookupDone) { CD.IsLookupDone = true; - CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName); + CD.II = &getState()->getStateManager().getContext().Idents.get( + CD.getFunctionName()); } const IdentifierInfo *II = getCalleeIdentifier(); if (!II || II != CD.II) return false; + + const Decl *D = getDecl(); + // If CallDescription provides prefix names, use them to improve matching + // accuracy. + if (CD.QualifiedName.size() > 1 && D) { + const DeclContext *Ctx = D->getDeclContext(); + // See if we'll be able to match them all. + size_t NumUnmatched = CD.QualifiedName.size() - 1; + for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) { + if (NumUnmatched == 0) + break; + + if (const auto *ND = dyn_cast<NamespaceDecl>(Ctx)) { + if (ND->getName() == CD.QualifiedName[NumUnmatched - 1]) + --NumUnmatched; + continue; + } + + if (const auto *RD = dyn_cast<RecordDecl>(Ctx)) { + if (RD->getName() == CD.QualifiedName[NumUnmatched - 1]) + --NumUnmatched; + continue; + } + } + + if (NumUnmatched > 0) + return false; + } + return (CD.RequiredArgs == CallDescription::NoArgRequirement || CD.RequiredArgs == getNumArgs()); } @@ -433,6 +503,14 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, const ParmVarDecl *ParamDecl = *I; assert(ParamDecl && "Formal parameter has no decl?"); + // TODO: Support allocator calls. + if (Call.getKind() != CE_CXXAllocator) + if (Call.isArgumentConstructedDirectly(Idx)) + continue; + + // TODO: Allocators should receive the correct size and possibly alignment, + // determined in compile-time but not represented as arg-expressions, + // which makes getArgSVal() fail and return UnknownVal. SVal ArgVal = Call.getArgSVal(Idx); if (!ArgVal.isUnknown()) { Loc ParamLoc = SVB.makeLoc(MRMgr.getVarRegion(ParamDecl, CalleeCtx)); @@ -472,17 +550,18 @@ RuntimeDefinition AnyFunctionCall::getRuntimeDefinition() const { return RuntimeDefinition(Decl); } - SubEngine *Engine = getState()->getStateManager().getOwningEngine(); - AnalyzerOptions &Opts = Engine->getAnalysisManager().options; + SubEngine &Engine = getState()->getStateManager().getOwningEngine(); + AnalyzerOptions &Opts = Engine.getAnalysisManager().options; // Try to get CTU definition only if CTUDir is provided. - if (!Opts.naiveCTUEnabled()) + if (!Opts.IsNaiveCTUEnabled) return {}; cross_tu::CrossTranslationUnitContext &CTUCtx = - *Engine->getCrossTranslationUnitContext(); + *Engine.getCrossTranslationUnitContext(); llvm::Expected<const FunctionDecl *> CTUDeclOrError = - CTUCtx.getCrossTUDefinition(FD, Opts.getCTUDir(), Opts.getCTUIndexName()); + CTUCtx.getCrossTUDefinition(FD, Opts.CTUDir, Opts.CTUIndexName, + Opts.DisplayCTUProgress); if (!CTUDeclOrError) { handleAllErrors(CTUDeclOrError.takeError(), @@ -758,7 +837,7 @@ const BlockDataRegion *BlockCall::getBlockRegion() const { ArrayRef<ParmVarDecl*> BlockCall::parameters() const { const BlockDecl *D = getDecl(); if (!D) - return nullptr; + return None; return D->parameters(); } @@ -1008,7 +1087,7 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, Selector Sel) const { assert(IDecl); AnalysisManager &AMgr = - getState()->getStateManager().getOwningEngine()->getAnalysisManager(); + getState()->getStateManager().getOwningEngine().getAnalysisManager(); // If the class interface is declared inside the main file, assume it is not // subcassed. // TODO: It could actually be subclassed if the subclass is private as well. @@ -1290,28 +1369,20 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, const Stmt *CallSite = CalleeCtx->getCallSite(); if (CallSite) { - if (const CallExpr *CE = dyn_cast<CallExpr>(CallSite)) - return getSimpleCall(CE, State, CallerCtx); - - switch (CallSite->getStmtClass()) { - case Stmt::CXXConstructExprClass: - case Stmt::CXXTemporaryObjectExprClass: { - SValBuilder &SVB = State->getStateManager().getSValBuilder(); - const auto *Ctor = cast<CXXMethodDecl>(CalleeCtx->getDecl()); - Loc ThisPtr = SVB.getCXXThis(Ctor, CalleeCtx); - SVal ThisVal = State->getSVal(ThisPtr); - - return getCXXConstructorCall(cast<CXXConstructExpr>(CallSite), - ThisVal.getAsRegion(), State, CallerCtx); - } - case Stmt::CXXNewExprClass: - return getCXXAllocatorCall(cast<CXXNewExpr>(CallSite), State, CallerCtx); - case Stmt::ObjCMessageExprClass: - return getObjCMethodCall(cast<ObjCMessageExpr>(CallSite), - State, CallerCtx); - default: - llvm_unreachable("This is not an inlineable statement."); - } + if (CallEventRef<> Out = getCall(CallSite, State, CallerCtx)) + return Out; + + // All other cases are handled by getCall. + assert(isa<CXXConstructExpr>(CallSite) && + "This is not an inlineable statement"); + + SValBuilder &SVB = State->getStateManager().getSValBuilder(); + const auto *Ctor = cast<CXXMethodDecl>(CalleeCtx->getDecl()); + Loc ThisPtr = SVB.getCXXThis(Ctor, CalleeCtx); + SVal ThisVal = State->getSVal(ThisPtr); + + return getCXXConstructorCall(cast<CXXConstructExpr>(CallSite), + ThisVal.getAsRegion(), State, CallerCtx); } // Fall back to the CFG. The only thing we haven't handled yet is @@ -1338,3 +1409,16 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, E.getAs<CFGBaseDtor>().hasValue(), State, CallerCtx); } + +CallEventRef<> CallEventManager::getCall(const Stmt *S, ProgramStateRef State, + const LocationContext *LC) { + if (const auto *CE = dyn_cast<CallExpr>(S)) { + return getSimpleCall(CE, State, LC); + } else if (const auto *NE = dyn_cast<CXXNewExpr>(S)) { + return getCXXAllocatorCall(NE, State, LC); + } else if (const auto *ME = dyn_cast<ObjCMessageExpr>(S)) { + return getObjCMethodCall(ME, State, LC); + } else { + return nullptr; + } +} |