int main(int argc, char **argv) { AnalyzerOptions *options = extractOptions(argc, argv); Program *program = new Program(options); outputProgramRepresentation(program, options); if (options->statistics()) TimingPerformance::generateReport(); }
/// Returns true if the function in \p CalleeADC may be inlined in general. /// /// This checks static properties of the function, such as its signature and /// CFG, to determine whether the analyzer should ever consider inlining it, /// in any context. static bool mayInlineDecl(AnalysisDeclContext *CalleeADC, AnalyzerOptions &Opts) { // FIXME: Do not inline variadic calls. if (CallEvent::isVariadic(CalleeADC->getDecl())) return false; // Check certain C++-related inlining policies. ASTContext &Ctx = CalleeADC->getASTContext(); if (Ctx.getLangOpts().CPlusPlus) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeADC->getDecl())) { // Conditionally control the inlining of template functions. if (!Opts.mayInlineTemplateFunctions()) if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) return false; // Conditionally control the inlining of C++ standard library functions. if (!Opts.mayInlineCXXStandardLibrary()) if (Ctx.getSourceManager().isInSystemHeader(FD->getLocation())) if (IsInStdNamespace(FD)) return false; // Conditionally control the inlining of methods on objects that look // like C++ containers. if (!Opts.mayInlineCXXContainerMethods()) if (!Ctx.getSourceManager().isInMainFile(FD->getLocation())) if (isContainerMethod(Ctx, FD)) return false; // Conditionally control the inlining of the destructor of C++ shared_ptr. // We don't currently do a good job modeling shared_ptr because we can't // see the reference count, so treating as opaque is probably the best // idea. if (!Opts.mayInlineCXXSharedPtrDtor()) if (isCXXSharedPtrDtor(FD)) return false; } } // It is possible that the CFG cannot be constructed. // Be safe, and check if the CalleeCFG is valid. const CFG *CalleeCFG = CalleeADC->getCFG(); if (!CalleeCFG) return false; // Do not inline large functions. if (CalleeCFG->getNumBlockIDs() > Opts.getMaxInlinableSize()) return false; // It is possible that the live variables analysis cannot be // run. If so, bail out. if (!CalleeADC->getAnalysis<RelaxedLiveVariables>()) return false; return true; }
/// Returns true if the function in \p CalleeADC may be inlined in general. /// /// This checks static properties of the function, such as its signature and /// CFG, to determine whether the analyzer should ever consider inlining it, /// in any context. static bool mayInlineDecl(const CallEvent &Call, AnalysisDeclContext *CalleeADC, AnalyzerOptions &Opts) { // FIXME: Do not inline variadic calls. if (Call.isVariadic()) return false; // Check certain C++-related inlining policies. ASTContext &Ctx = CalleeADC->getASTContext(); if (Ctx.getLangOpts().CPlusPlus) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeADC->getDecl())) { // Conditionally control the inlining of template functions. if (!Opts.mayInlineTemplateFunctions()) if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) return false; // Conditionally control the inlining of C++ standard library functions. if (!Opts.mayInlineCXXStandardLibrary()) if (Ctx.getSourceManager().isInSystemHeader(FD->getLocation())) if (IsInStdNamespace(FD)) return false; // Conditionally control the inlining of methods on objects that look // like C++ containers. if (!Opts.mayInlineCXXContainerCtorsAndDtors()) if (!Ctx.getSourceManager().isFromMainFile(FD->getLocation())) if (isContainerCtorOrDtor(Ctx, FD)) return false; } } // It is possible that the CFG cannot be constructed. // Be safe, and check if the CalleeCFG is valid. const CFG *CalleeCFG = CalleeADC->getCFG(); if (!CalleeCFG) return false; // Do not inline large functions. if (CalleeCFG->getNumBlockIDs() > Opts.getMaxInlinableSize()) return false; // It is possible that the live variables analysis cannot be // run. If so, bail out. if (!CalleeADC->getAnalysis<RelaxedLiveVariables>()) return false; return true; }
AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, const LangOptions &lang, const PathDiagnosticConsumers &PDC, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, AnalyzerOptions &Options, CodeInjector *injector) : AnaCtxMgr(Options.UnoptimizedCFG, Options.includeImplicitDtorsInCFG(), /*AddInitializers=*/true, Options.includeTemporaryDtorsInCFG(), Options.includeLifetimeInCFG(), // Adding LoopExit elements to the CFG is a requirement for loop // unrolling. Options.includeLoopExitInCFG() || Options.shouldUnrollLoops(), Options.shouldSynthesizeBodies(), Options.shouldConditionalizeStaticInitializers(), /*addCXXNewAllocator=*/true, injector), Ctx(ctx), Diags(diags), LangOpts(lang), PathConsumers(PDC), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr), options(Options) { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); }
AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, const LangOptions &lang, const PathDiagnosticConsumers &PDC, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, AnalyzerOptions &Options) : AnaCtxMgr(Options.UnoptimizedCFG, /*AddImplicitDtors=*/true, /*AddInitializers=*/true, Options.includeTemporaryDtorsInCFG(), Options.shouldSynthesizeBodies()), Ctx(ctx), Diags(diags), LangOpts(lang), PathConsumers(PDC), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr), options(Options) { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); }
void DataFlowAnalysis::run(Program *program) { AnalyzerOptions *options = program->options; bool verbose = options->verbose(); /* Set the PAG options as specified on the command line. */ setPagOptions(*options); setPrefixedPagOptions(options, p_impl); /* Build the program's ICFG if necessary. */ if (program->icfg == NULL) program->icfg = createICFG(program, options); /* Run this analysis. */ if (verbose) { std::cout << "performing analysis " << identifier() << " ... " << std::flush; } TimingPerformance *nestedTimer = new TimingPerformance("Actual data-flow analysis " + identifier() + ":"); p_impl->analysisDoit(program->icfg); delete nestedTimer; if (verbose) std::cout << "done" << std::endl; /* Make results persistent. We always do this (by default) to avoid * problems with garbage collected results. */ p_impl->makePersistent(); #if HAVE_PAG /* If requested, compute call strings from PAG's call string data, and * store them in the ICFG. */ if (options->computeCallStrings()) computeCallStrings(program); #endif }
static std::unique_ptr<WorkList> generateWorkList(AnalyzerOptions &Opts) { switch (Opts.getExplorationStrategy()) { case AnalyzerOptions::ExplorationStrategyKind::DFS: return WorkList::makeDFS(); case AnalyzerOptions::ExplorationStrategyKind::BFS: return WorkList::makeBFS(); case AnalyzerOptions::ExplorationStrategyKind::BFSBlockDFSContents: return WorkList::makeBFSBlockDFSContents(); case AnalyzerOptions::ExplorationStrategyKind::UnexploredFirst: return WorkList::makeUnexploredFirst(); case AnalyzerOptions::ExplorationStrategyKind::UnexploredFirstQueue: return WorkList::makeUnexploredFirstPriorityQueue(); default: llvm_unreachable("Unexpected case"); } }
static CallInlinePolicy mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred, AnalyzerOptions &Opts) { const LocationContext *CurLC = Pred->getLocationContext(); const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame(); switch (Call.getKind()) { case CE_Function: case CE_Block: break; case CE_CXXMember: case CE_CXXMemberOperator: if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions)) return CIP_DisallowedAlways; break; case CE_CXXConstructor: { if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors)) return CIP_DisallowedAlways; const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call); // FIXME: We don't handle constructors or destructors for arrays properly. // Even once we do, we still need to be careful about implicitly-generated // initializers for array fields in default move/copy constructors. const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion(); if (Target && isa<ElementRegion>(Target)) return CIP_DisallowedOnce; // FIXME: This is a hack. We don't use the correct region for a new // expression, so if we inline the constructor its result will just be // thrown away. This short-term hack is tracked in <rdar://problem/12180598> // and the longer-term possible fix is discussed in PR12014. const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr(); if (const Stmt *Parent = CurLC->getParentMap().getParent(CtorExpr)) if (isa<CXXNewExpr>(Parent)) return CIP_DisallowedOnce; // Inlining constructors requires including initializers in the CFG. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers"); (void)ADC; // If the destructor is trivial, it's always safe to inline the constructor. if (Ctor.getDecl()->getParent()->hasTrivialDestructor()) break; // For other types, only inline constructors if destructor inlining is // also enabled. if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return CIP_DisallowedAlways; // FIXME: This is a hack. We don't handle temporary destructors // right now, so we shouldn't inline their constructors. if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete) if (!Target || !isa<DeclRegion>(Target)) return CIP_DisallowedOnce; break; } case CE_CXXDestructor: { if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return CIP_DisallowedAlways; // Inlining destructors requires building the CFG correctly. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors"); (void)ADC; const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call); // FIXME: We don't handle constructors or destructors for arrays properly. const MemRegion *Target = Dtor.getCXXThisVal().getAsRegion(); if (Target && isa<ElementRegion>(Target)) return CIP_DisallowedOnce; break; } case CE_CXXAllocator: if (Opts.mayInlineCXXAllocator()) break; // Do not inline allocators until we model deallocators. // This is unfortunate, but basically necessary for smart pointers and such. return CIP_DisallowedAlways; case CE_ObjCMessage: if (!Opts.mayInlineObjCMethod()) return CIP_DisallowedAlways; if (!(Opts.getIPAMode() == IPAK_DynamicDispatch || Opts.getIPAMode() == IPAK_DynamicDispatchBifurcate)) return CIP_DisallowedAlways; break; } return CIP_Allowed; }
ExprEngine::CallInlinePolicy ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred, AnalyzerOptions &Opts, const ExprEngine::EvalCallOptions &CallOpts) { const LocationContext *CurLC = Pred->getLocationContext(); const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame(); switch (Call.getKind()) { case CE_Function: case CE_Block: break; case CE_CXXMember: case CE_CXXMemberOperator: if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions)) return CIP_DisallowedAlways; break; case CE_CXXConstructor: { if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors)) return CIP_DisallowedAlways; const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call); const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr(); // FIXME: ParentMap is slow and ugly. The callee should provide the // necessary context. Ideally as part of the call event, or maybe as part of // location context. const Stmt *ParentExpr = CurLC->getParentMap().getParent(CtorExpr); if (ParentExpr && isa<CXXNewExpr>(ParentExpr) && !Opts.mayInlineCXXAllocator()) return CIP_DisallowedOnce; // FIXME: We don't handle constructors or destructors for arrays properly. // Even once we do, we still need to be careful about implicitly-generated // initializers for array fields in default move/copy constructors. // We still allow construction into ElementRegion targets when they don't // represent array elements. if (CallOpts.IsArrayConstructorOrDestructor) return CIP_DisallowedOnce; // Inlining constructors requires including initializers in the CFG. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers"); (void)ADC; // If the destructor is trivial, it's always safe to inline the constructor. if (Ctor.getDecl()->getParent()->hasTrivialDestructor()) break; // For other types, only inline constructors if destructor inlining is // also enabled. if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return CIP_DisallowedAlways; // FIXME: This is a hack. We don't handle temporary destructors // right now, so we shouldn't inline their constructors. if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete) if (CallOpts.IsConstructorWithImproperlyModeledTargetRegion) return CIP_DisallowedOnce; break; } case CE_CXXDestructor: { if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return CIP_DisallowedAlways; // Inlining destructors requires building the CFG correctly. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors"); (void)ADC; // FIXME: We don't handle constructors or destructors for arrays properly. if (CallOpts.IsArrayConstructorOrDestructor) return CIP_DisallowedOnce; break; } case CE_CXXAllocator: if (Opts.mayInlineCXXAllocator()) break; // Do not inline allocators until we model deallocators. // This is unfortunate, but basically necessary for smart pointers and such. return CIP_DisallowedAlways; case CE_ObjCMessage: if (!Opts.mayInlineObjCMethod()) return CIP_DisallowedAlways; if (!(Opts.getIPAMode() == IPAK_DynamicDispatch || Opts.getIPAMode() == IPAK_DynamicDispatchBifurcate)) return CIP_DisallowedAlways; break; } return CIP_Allowed; }