void add_thread (ThreadId t, CFG cfg, VarNameIt sh_begin, VarNameIt sh_end) { auto it = m_cfg_map.find (t); if (it != m_cfg_map.end ()) return; std::set<varname_t> shared_vs; shared_vs.insert (sh_begin, sh_end); std::set<varname_t> local_vs; for (auto &b: boost::make_iterator_range (cfg.begin (), cfg.end ())) { for (auto &s: b) { auto ls = s.getLive (); if (ls.defs_begin () != ls.defs_end ()) local_vs.insert (ls.defs_begin (), ls.defs_end ()); if (ls.uses_begin () != ls.uses_end ()) local_vs.insert (ls.uses_begin (), ls.uses_end ()); } } set_difference (local_vs, shared_vs); m_cfg_map.insert (std::make_pair (t, cfg)); m_gv_map.insert (std::make_pair (t, shared_vs)); m_lv_map.insert (std::make_pair (t, local_vs)); }
void MainWindow::on_actionLoad_XML_triggered() { scene->clear(); graph.clear(); QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", "Files (*.xml)", NULL); CFG cfg = parser.getCFG(fileName); // add all blocks for(Block block : cfg.getBlocks()) { Node* node = new Node(block.getName(), 50, 50); node->setX(qrand() % ((500 + 1) - (-500)) + (-500)); node->setY(qrand() % ((500 + 1) - (-500)) + (-500)); scene->addItem(node); graph.addNode(node); } // add all edges for(Block block : cfg.getBlocks()) { AbstractNode* from = graph.getNode(block.getName()); for(QString succName : block.getSuccessors()) { AbstractNode* to = graph.getNode(succName); EdgeItem* edge = new EdgeItem(from,to,true); edge->adjust(); scene->addItem(edge); graph.addEdge(from,to,edge); } } graph.setStart(graph.getNode(cfg.getStart().getName())); }
void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, SetOfConstDecls *VisitedCallees) { if (!D->hasBody()) return; Mode = getModeForDecl(D, Mode); if (Mode == AM_None) return; // DisplayFunction(D, Mode, IMode); CFG *DeclCFG = Mgr->getCFG(D); if (DeclCFG) { unsigned CFGSize = DeclCFG->size(); MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize; } // Clear the AnalysisManager of old AnalysisDeclContexts. Mgr->ClearContexts(); myLiveVariables* L = /*Mgr->getAnalysis<LiveVariables>(D)*/myLiveVariables::create(*(Mgr->getAnalysisDeclContext(D)), Mgr->getASTContext().getSourceManager()); L->dumpBlockLiveness(Mgr->getASTContext().getSourceManager()); // BugReporter BR(*Mgr); // if (Mode & AM_Syntax) // checkerMgr->runCheckersOnASTBody(D, *Mgr, BR); // if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) { // RunPathSensitiveChecks(D, IMode, VisitedCallees); // if (IMode != ExprEngine::Inline_Minimal) // NumFunctionsAnalyzed++; // } }
TEST_F(TestCFG, RecursionElimination) { cfg << "<S> ::= <S>a|b"; CFG expected; expected << "<S> ::= b<S'>"; expected << "<S'> ::= a<S'>|"; EXPECT_EQ(expected, cfg.withoutRecursion()); cfg.clear(); cfg << "<S> ::= <S><S>a|b<A>"; cfg << "<A> ::= b<B>c|<A>e|"; cfg << "<B> ::= <B>a|<B>b|c|d|"; expected.clear(); expected << "<S> ::= b<A><S'>"; expected << "<S'> ::= <S>a<S'>|"; expected << "<A> ::= b<B>c<A'>|<A'>"; expected << "<A'> ::= e<A'>|"; expected << "<B> ::= c<B'>|d<B'>|<B'>"; expected << "<B'> ::= a<B'>|b<B'>|"; EXPECT_EQ(expected, cfg.withoutRecursion()); // cfg.clear(); // cfg << "<S> ::= <A>a|a"; // cfg << "<A> ::= <B>b|b"; // cfg << "<B> ::= <S>c|c"; // expected.clear(); // expected << "<S> ::= <A>a|a"; // expected << "<A> ::= <B>b|b"; // expected << "<B> ::= bac<B'>|ac<B'>|c<B'>"; // expected << "<B'> ::= bac<B'>|"; // EXPECT_EQ(expected, cfg.withoutRecursion()); }
CFG CFGGenerator::getCFG(FunctionDefinition& f) { CFG result; result.fStart = result.newBlock(); result.fCurrent = result.fStart; this->addStatement(result, &f.fBody); result.newBlock(); result.fExit = result.fCurrent; return result; }
void lfort::runUninitializedVariablesAnalysis( const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats) { CFGBlockValues vals(cfg); vals.computeSetOfDeclarations(dc); if (vals.hasNoDeclarations()) return; stats.NumVariablesAnalyzed = vals.getNumEntries(); // Precompute which expressions are uses and which are initializations. ClassifyRefs classification(ac); cfg.VisitBlockStmts(classification); // Mark all variables uninitialized at the entry. const CFGBlock &entry = cfg.getEntry(); ValueVector &vec = vals.getValueVector(&entry); const unsigned n = vals.getNumEntries(); for (unsigned j = 0; j < n ; ++j) { vec[j] = Uninitialized; } // Proceed with the workist. DataflowWorklist worklist(cfg, *ac.getAnalysis<PostOrderCFGView>()); llvm::BitVector previouslyVisited(cfg.getNumBlockIDs()); worklist.enqueueSuccessors(&cfg.getEntry()); llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false); wasAnalyzed[cfg.getEntry().getBlockID()] = true; PruneBlocksHandler PBH(cfg.getNumBlockIDs()); while (const CFGBlock *block = worklist.dequeue()) { PBH.currentBlock = block->getBlockID(); // Did the block change? bool changed = runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, PBH); ++stats.NumBlockVisits; if (changed || !previouslyVisited[block->getBlockID()]) worklist.enqueueSuccessors(block); previouslyVisited[block->getBlockID()] = true; } if (!PBH.hadAnyUse) return; // Run through the blocks one more time, and report uninitialized variabes. for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { const CFGBlock *block = *BI; if (PBH.hadUse[block->getBlockID()]) { runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler); ++stats.NumBlockVisits; } } }
void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl, const char* sep) const { // Print the store. GRStateManager &Mgr = getStateManager(); Mgr.getStoreManager().print(getStore(), Out, nl, sep); // Print Subexpression bindings. bool isFirst = true; for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { if (C.isBlkExpr(I.getKey())) continue; if (isFirst) { Out << nl << nl << "Sub-Expressions:" << nl; isFirst = false; } else { Out << nl; } Out << " (" << (void*) I.getKey() << ") "; LangOptions LO; // FIXME. I.getKey()->printPretty(Out, 0, PrintingPolicy(LO)); Out << " : " << I.getData(); } // Print block-expression bindings. isFirst = true; for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { if (!C.isBlkExpr(I.getKey())) continue; if (isFirst) { Out << nl << nl << "Block-level Expressions:" << nl; isFirst = false; } else { Out << nl; } Out << " (" << (void*) I.getKey() << ") "; LangOptions LO; // FIXME. I.getKey()->printPretty(Out, 0, PrintingPolicy(LO)); Out << " : " << I.getData(); } Mgr.getConstraintManager().print(this, Out, nl, sep); // Print checker-specific data. for (std::vector<Printer*>::iterator I = Mgr.Printers.begin(), E = Mgr.Printers.end(); I != E; ++I) { (*I)->Print(Out, this, nl, sep); } }
int FunctionMetadata::calculateNumUserVisibleVRegs() { SourceInfo* source_info = source.get(); CFG* cfg = source_info->cfg; assert(cfg && "We don't calculate the CFG inside this function because it can raise an exception and its " "therefore not safe to call at every point"); if (!cfg->hasVregsAssigned()) { ScopeInfo* scope_info = source->getScopeInfo(); cfg->assignVRegs(param_names, scope_info); } return cfg->sym_vreg_map_user_visible.size(); }
bool operator == (const CFG& cfg1, const CFG& cfg2) { if (cfg1.getTerminals() != cfg2.getTerminals()) return false; if (cfg1.getRules() != cfg2.getRules()) return false; if (cfg1.getVariables() != cfg2.getVariables()) return false; if (cfg1.getStartSymbol() != cfg2.getStartSymbol()) return false; return true; }
KernelStatistics *KernelStatistics::computeKernelStatistics(AnalysisDeclContext &AC, StringRef name, CompilerKnownClasses &compilerClasses) { // No CFG? Bail out. CFG *cfg = AC.getCFG(); if (!cfg) return 0; #ifdef DEBUG_ANALYSIS cfg->viewCFG(AC.getASTContext().getLangOpts()); #endif KernelStatsImpl *KS = new KernelStatsImpl(AC, name, compilerClasses); KS->runOnAllBlocks(); return new KernelStatistics(KS); }
int main(int argc, char **argv) { Manager manager; PropList props; // LOADER(props) = &Loader::LOADER_Gliss_PowerPC; try { WorkSpace *fw = manager.load(argv[1], props); // Find main CFG cout << "Looking for the main CFG\n"; CFG *cfg = fw->getCFGInfo()->findCFG("main"); if(cfg == 0) { cerr << "ERROR: cannot find main !\n"; return 1; } else cout << "main found at 0x" << cfg->address() << '\n'; // Build dominance Dominance dom; dom.processCFG(fw, cfg); // Display dominance information for(CFG::BBIterator bb1(cfg); bb1; bb1++) { bool first = true; cout << bb1->number() << " dominates {"; for(CFG::BBIterator bb2(cfg); bb2; bb2++) if(Dominance::dominates(bb1, bb2)) { if(first) first = false; else cout << ", "; cout << bb2->number(); } cout << "}\n"; } // Display the result cout << "SUCCESS\n"; } catch(LoadException e) { cerr << "ERROR: " << e.message() << '\n'; exit(1); } return 0; }
std::string CFG::varcnt(void) { int cnt = 0; char cntvar[64] = {0}; CFG *root = this; while (NULL != root->prev()) { root = root->prev(); } cnt = root->_varcnt_(); if (0 != cnt) { snprintf(cntvar, sizeof(cntvar), "0x%X", cnt * PARAM_SIZE); } _D(LOG_DEBUG, "variable count on %s - %d", root->label().c_str(), cnt); return cntvar; }
inline void printState(const LR0State& state, const CFG& cfg) { ECHO("Kernel:"); for (auto& item : state.kernel) { ECHO(cfg.toReadableForm(cfg[item.productionNumber])); // TRACE(item.position); // TRACE(item.targetState); } ECHO("Items:"); for (auto& item : state.items) { ECHO(cfg.toReadableForm(cfg[item.productionNumber])); TRACE(item.position); TRACE(item.targetState); TRACE(static_cast<int>(item.action)); } // TRACE(state.kernel.size()); // TRACE(state.items.size()); ECHO(""); }
int main(int argc, char *argv[]) { //regex_test(); /* CFG<Parse_data> *cfg = read_grammar(ss.str()); if (cfg) cout << endl << cfg->str() << endl << endl; */ SymbolTable *symtab = new SymbolTable(); Lexer<int> *lexer = read_lexer(file_to_string(argv[1]), symtab); CFG<int> *cfg = read_grammar(file_to_string(argv[2]), symtab); //cout << cfg->dfa->str() << endl << endl; cfg->parse(lexer->lex(file_to_string(argv[3]), true, true), true); // for (int i = 0; i < lexer->rules.size()-2; ++i) { // cout << lexer->rules[i].regex.dfa->str() << endl; // } return 0; }
inline void expandState(LR0State& state, const CFG& cfg) { for (auto& item : state.items) { // TRACE(item.productionNumber); const Production& prod = cfg[item.productionNumber]; if (item.position >= prod.size()) { continue; } auto symbol = prod[item.position]; if (cfg.isNonTerminal(symbol)) { for (std::size_t i = 0; i < cfg.size(); i++) { const Production& production = cfg[i]; if (production.getName() == symbol) { state.items.emplace_back(LR0Item{i, 0}); } } } } }
void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, Callback &CB) { CFG *cfg = AC.getCFG(); if (!cfg) return; // Scan for reachable blocks from the entrance of the CFG. // If there are no unreachable blocks, we're done. llvm::BitVector reachable(cfg->getNumBlockIDs()); unsigned numReachable = scanMaybeReachableFromBlock(&cfg->getEntry(), PP, reachable); if (numReachable == cfg->getNumBlockIDs()) return; // If there aren't explicit EH edges, we should include the 'try' dispatch // blocks as roots. if (!AC.getCFGBuildOptions().AddEHEdges) { for (CFG::try_block_iterator I = cfg->try_blocks_begin(), E = cfg->try_blocks_end() ; I != E; ++I) { numReachable += scanMaybeReachableFromBlock(*I, PP, reachable); } if (numReachable == cfg->getNumBlockIDs()) return; } // There are some unreachable blocks. We need to find the root blocks that // contain code that should be considered unreachable. for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { const CFGBlock *block = *I; // A block may have been marked reachable during this loop. if (reachable[block->getBlockID()]) continue; DeadCodeScan DS(reachable, PP); numReachable += DS.scanBackwards(block, CB); if (numReachable == cfg->getNumBlockIDs()) return; } }
void ProgAnalysis::traverseCFG(CFG *cfg, std::set<CFG *> &cfgs, std::set<CFG *> &cfgs_done) { // Addition of rules only depends of whether the pds // is of type wpds::WPDS or not (all others inherit from wpds::ewpds::EWPDS). wali::wpds::ewpds::EWPDS *epds = 0; if(wpdsType != USING_WPDS) { epds = static_cast<wali::wpds::ewpds::EWPDS *>(pds); } const std::set<CFGEdge *> &edges = cfg->getEdges(); std::set<CFGEdge *>::const_iterator it; for(it = edges.begin(); it != edges.end(); it++) { CFGEdge *edge = *it; if(!edge->isCall()) { pds->add_rule(pds_state, edge->getSource()->getWpdsKey(), pds_state, edge->getTarget()->getWpdsKey(), edge->getWeight()); } else { CFG *callee = edge->getCallee(); if(wpdsType == USING_WPDS) { pds->add_rule(pds_state, edge->getSource()->getWpdsKey(), pds_state, callee->getEntry()->getWpdsKey(), edge->getTarget()->getWpdsKey(), edge->getWeight()); } else { epds->add_rule(pds_state, edge->getSource()->getWpdsKey(), pds_state, callee->getEntry()->getWpdsKey(), edge->getTarget()->getWpdsKey(), edge->getWeight(), edge->getMergeFn()); } if(cfgs_done.find(callee) == cfgs_done.end()) { cfgs.insert(callee); } } // store the weight if(!se.is_valid()) { se = edge->getWeight(); } } }
void AnalysisConsumer::AnalyzeFunction(CFG& cfg, ASTContext &contex, unsigned &report_ctr) { // Compute the ranges information. cfg.print(llvm::outs(),LangOptions()); APAbstractDomain Dom(cfg); Dom.InitializeValues(cfg); APChecker Observer(contex,diagnostics_engine_, preprocessor_ptr_); Dom.getAnalysisData().Observer = &Observer; Dom.getAnalysisData().setContext(contex); Solver S(Dom); S.runOnCFG(cfg, true); Observer.ObserveFixedPoint(true, compute_diff_, report_ctr); }
void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D, AnalysisManager &mgr, BugReporter &BR) const { CFG *cfg = mgr.getCFG(D); if (!cfg) return; // A list of variables referenced in possibly overflowing malloc operands. llvm::SmallVector<MallocOverflowCheck, 2> PossibleMallocOverflows; for (CFG::iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) { CFGBlock *block = *it; for (CFGBlock::iterator bi = block->begin(), be = block->end(); bi != be; ++bi) { if (const CFGStmt *CS = bi->getAs<CFGStmt>()) { if (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) { // Get the callee. const FunctionDecl *FD = TheCall->getDirectCallee(); if (!FD) return; // Get the name of the callee. If it's a builtin, strip off the prefix. IdentifierInfo *FnInfo = FD->getIdentifier(); if (!FnInfo) return; if (FnInfo->isStr ("malloc") || FnInfo->isStr ("_MALLOC")) { if (TheCall->getNumArgs() == 1) CheckMallocArgument(PossibleMallocOverflows, TheCall->getArg(0), mgr.getASTContext()); } } } } } OutputPossibleOverflows(PossibleMallocOverflows, D, BR, mgr); }
/* Dump user databases */ int main(){ umask(066); try { cfg.read(CFG_FILE); /* read parameters from the config file */ local_dump_db(cfg, 0, NULL); } catch(Err e) { process_result(e); } catch(Json::Err e) { process_result(e); } catch(JsonDB::Err e){ process_result(e); } catch (Exc e) { process_result(e); } exit(0); }
parser::LL1::LL1(const CFG& cfg) : Parser(cfg) { cfg.prepareFirst(); for (std::size_t i = 0; i < cfg.size(); i++) { const Production& prod = cfg[i]; std::string prodName = prod.getName(); auto& row = table[prodName]; for (auto& symbol : prod.getFirstSet()) { if (row.count(symbol) > 0) { conflict = true; return; } row[symbol] = i; } if (prod.isNullable()) { auto follow = cfg.follow(prodName); if (cfg.endable(prodName)) { follow.insert(END_OF_SENTENCE); } for (auto& symbol : follow) { if (row.count(symbol) > 0) { conflict = true; return; } row[symbol] = i; } } } // for (auto& pair : table) { // TRACE(pair.first); // for (auto& p : pair.second) { // ECHO(p.first + " -> " + std::to_string(p.second)); // } // } }
void clang::runUninitializedVariablesAnalysis( const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats) { CFGBlockValues vals(cfg); vals.computeSetOfDeclarations(dc); if (vals.hasNoDeclarations()) return; stats.NumVariablesAnalyzed = vals.getNumEntries(); // Mark all variables uninitialized at the entry. const CFGBlock &entry = cfg.getEntry(); for (CFGBlock::const_succ_iterator i = entry.succ_begin(), e = entry.succ_end(); i != e; ++i) { if (const CFGBlock *succ = *i) { ValueVector &vec = vals.getValueVector(&entry, succ); const unsigned n = vals.getNumEntries(); for (unsigned j = 0; j < n ; ++j) { vec[j] = Uninitialized; } } } // Proceed with the workist. DataflowWorklist worklist(cfg); llvm::BitVector previouslyVisited(cfg.getNumBlockIDs()); worklist.enqueueSuccessors(&cfg.getEntry()); llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false); wasAnalyzed[cfg.getEntry().getBlockID()] = true; while (const CFGBlock *block = worklist.dequeue()) { // Did the block change? bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed); ++stats.NumBlockVisits; if (changed || !previouslyVisited[block->getBlockID()]) worklist.enqueueSuccessors(block); previouslyVisited[block->getBlockID()] = true; } // Run through the blocks one more time, and report uninitialized variabes. for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { const CFGBlock *block = *BI; if (wasAnalyzed[block->getBlockID()]) { runOnBlock(block, cfg, ac, vals, wasAnalyzed, &handler); ++stats.NumBlockVisits; } } }
void DefinednessBBAnalyzer::processBB(Map &starting, CFGBlock *block) const { DefinednessVisitor visitor(starting); for (int i = 0; i < block->body.size(); i++) { block->body[i]->accept(&visitor); } if (block == cfg->getStartingBlock() && arguments) { arguments->accept(&visitor); } if (VERBOSITY("analysis") >= 2) { printf("At end of block %d:\n", block->idx); for (const auto &p : starting) { printf("%s: %d\n", p.first.c_str(), p.second); } } }
void DefinednessBBAnalyzer::processBB(Map& starting, CFGBlock* block) const { DefinednessVisitor visitor(starting); if (block == cfg->getStartingBlock() && arg_names.args) { for (auto e : (*arg_names.args)) visitor._doSet(e); if (arg_names.vararg->size()) visitor._doSet(*arg_names.vararg); if (arg_names.kwarg->size()) visitor._doSet(*arg_names.kwarg); } for (int i = 0; i < block->body.size(); i++) { block->body[i]->accept(&visitor); } if (VERBOSITY("analysis") >= 2) { printf("At end of block %d:\n", block->idx); for (const auto& p : starting) { printf("%s: %d\n", p.first.c_str(), p.second); } } }
void pMBUfactHandler::doInsensitiveAnalysis(CFG& cfg) { //- 1. collect starting points (into relevant_ecrs) cfg.traverseRootNodes(pMBUfactHandler::collectStartingPoints); //- 2. follow assignment edges backwards suco_set<ECR *> worklist; worklist.Union(pMBUfactHandler::relevant_ecrs); while(!worklist.IsEmpty()){ ECR& ecr = *worklist.RemoveHead(); //- for each ecr in worklist: traverse its aos suco_iterator<AO *> aoi(ecr.getAOset()); while(aoi.Iterate()){ // 1. collect locs in results if(aoi.Current()->isLocArgRet()){ pMBUfactHandler::results.Insert(aoi.Current()); } // 2. follow incl-edges backwards //NOTE: technically, only want to follow "copy" edges, // and skip assignments from a (+) node; but the existence // of such a node would've rendered the starting point // "unsafe", so it should never be encountered!? suco_iterator<TCassignEdge *> edi(aoi.Current()->getIncomingAssignEdges()); while(edi.Iterate()){ ECR& fecr = edi.Current()->getFrom().getECR(); if(!pMBUfactHandler::relevant_ecrs.Contains(&fecr)){ suco_set<ECR *> fecr_aliases; fecr.collectAliasECRs(fecr_aliases); //- using this because getAliasECRs filters loc/arg/ret // fecr_aliases.Subtract(pMBUfactHandler::relevant_ecrs); //-TODO: avoid repetition pMBUfactHandler::relevant_ecrs.Union(fecr_aliases); worklist.UnionConsume(fecr_aliases); } } } } }
void SystemDependenceGraph::build() { boost::unordered_map<CFGVertex, Vertex> cfgVerticesToSdgVertices; boost::unordered_map<SgNode*, Vertex> astNodesToSdgVertices; //map<SgFunctionCallExp*, vector<SDGNode*> > funcCallToArgs; vector<CallSiteInfo> functionCalls; map<SgNode*, vector<Vertex> > actualInParameters; map<SgNode*, vector<Vertex> > actualOutParameters; map<SgNode*, Vertex> formalInParameters; map<SgNode*, Vertex> formalOutParameters; vector<SgFunctionDefinition*> funcDefs = SageInterface::querySubTree<SgFunctionDefinition>(project_, V_SgFunctionDefinition); foreach (SgFunctionDefinition* funcDef, funcDefs) { SgFunctionDeclaration* funcDecl = funcDef->get_declaration(); CFG* cfg = new CFG(funcDef, cfgNodefilter_); functionsToCFGs_[funcDecl] = cfg; // For each function, build an entry node for it. SDGNode* entry = new SDGNode(SDGNode::Entry); entry->astNode = funcDef; //entry->funcDef = funcDef; Vertex entryVertex = addVertex(entry); functionsToEntries_[funcDecl] = entryVertex; // Add all out formal parameters to SDG. const SgInitializedNamePtrList& formalArgs = funcDecl->get_args(); foreach (SgInitializedName* initName, formalArgs) { // If the parameter is passed by reference, create a formal-out node. if (isParaPassedByRef(initName->get_type())) { SDGNode* formalOutNode = new SDGNode(SDGNode::FormalOut); formalOutNode->astNode = initName; Vertex formalOutVertex = addVertex(formalOutNode); formalOutParameters[initName] = formalOutVertex; // Add a CD edge from call node to this formal-out node. addTrueCDEdge(entryVertex, formalOutVertex); } } // A vertex representing the returned value. Vertex returnVertex; // If the function returns something, build a formal-out node. if (!isSgTypeVoid(funcDecl->get_type()->get_return_type())) { SDGNode* formalOutNode = new SDGNode(SDGNode::FormalOut); // Assign the function declaration to the AST node of this vertex to make // it possible to classify this node into the subgraph of this function. formalOutNode->astNode = funcDecl; returnVertex = addVertex(formalOutNode); formalOutParameters[funcDecl] = returnVertex; // Add a CD edge from call node to this formal-out node. addTrueCDEdge(entryVertex, returnVertex); } // Add all CFG vertices to SDG. foreach (CFGVertex cfgVertex, boost::vertices(*cfg)) { if (cfgVertex == cfg->getEntry() || cfgVertex == cfg->getExit()) continue; SgNode* astNode = (*cfg)[cfgVertex]->getNode(); // If this node is an initialized name and it is a parameter, make it // as a formal in node. SgInitializedName* initName = isSgInitializedName(astNode); if (initName && isSgFunctionParameterList(initName->get_parent())) { SDGNode* formalInNode = new SDGNode(SDGNode::FormalIn); formalInNode->astNode = initName; Vertex formalInVertex = addVertex(formalInNode); formalInParameters[initName] = formalInVertex; cfgVerticesToSdgVertices[cfgVertex] = formalInVertex; astNodesToSdgVertices[astNode] = formalInVertex; // Add a CD edge from call node to this formal-in node. addTrueCDEdge(entryVertex, formalInVertex); continue; } // Add a new node to SDG. SDGNode* newSdgNode = new SDGNode(SDGNode::ASTNode); //newSdgNode->cfgNode = (*cfg)[cfgVertex]; newSdgNode->astNode = astNode; Vertex sdgVertex = addVertex(newSdgNode); cfgVerticesToSdgVertices[cfgVertex] = sdgVertex; astNodesToSdgVertices[astNode] = sdgVertex; // Connect a vertex containing the return statement to the formal-out return vertex. if (isSgReturnStmt(astNode) || isSgReturnStmt(astNode->get_parent())) { SDGEdge* newEdge = new SDGEdge(SDGEdge::DataDependence); addEdge(sdgVertex, returnVertex, newEdge); } // If this CFG node contains a function call expression, extract its all parameters // and make them as actual-in nodes. if (SgFunctionCallExp* funcCallExpr = isSgFunctionCallExp(astNode)) { CallSiteInfo callInfo; callInfo.funcCall = funcCallExpr; callInfo.vertex = sdgVertex; // Change the node type. newSdgNode->type = SDGNode::FunctionCall; vector<SDGNode*> argsNodes; // Get the associated function declaration. SgFunctionDeclaration* funcDecl = funcCallExpr->getAssociatedFunctionDeclaration(); if (funcDecl == NULL) continue; ROSE_ASSERT(funcDecl); const SgInitializedNamePtrList& formalArgs = funcDecl->get_args(); SgExprListExp* args = funcCallExpr->get_args(); const SgExpressionPtrList& actualArgs = args->get_expressions(); if (formalArgs.size() != actualArgs.size()) { cout << "The following function has variadic arguments:\n"; cout << funcDecl->get_file_info()->get_filename() << endl; cout << funcDecl->get_name() << formalArgs.size() << " " << actualArgs.size() << endl; continue; } for (int i = 0, s = actualArgs.size(); i < s; ++i) { // Make sure that this parameter node is added to SDG then we // change its node type from normal AST node to a ActualIn arg. ROSE_ASSERT(astNodesToSdgVertices.count(actualArgs[i])); Vertex paraInVertex = astNodesToSdgVertices.at(actualArgs[i]); SDGNode* paraInNode = (*this)[paraInVertex]; paraInNode->type = SDGNode::ActualIn; actualInParameters[formalArgs[i]].push_back(paraInVertex); callInfo.inPara.push_back(paraInVertex); // Add a CD edge from call node to this actual-in node. addTrueCDEdge(sdgVertex, paraInVertex); // If the parameter is passed by reference, create a parameter-out node. if (isParaPassedByRef(formalArgs[i]->get_type())) { SDGNode* paraOutNode = new SDGNode(SDGNode::ActualOut); paraOutNode->astNode = actualArgs[i]; //argsNodes.push_back(paraInNode); // Add an actual-out parameter node. Vertex paraOutVertex = addVertex(paraOutNode); actualOutParameters[formalArgs[i]].push_back(paraOutVertex); callInfo.outPara.push_back(paraOutVertex); // Add a CD edge from call node to this actual-out node. addTrueCDEdge(sdgVertex, paraOutVertex); } } if (!isSgTypeVoid(funcDecl->get_type()->get_return_type())) { // If this function returns a value, create a actual-out vertex. SDGNode* paraOutNode = new SDGNode(SDGNode::ActualOut); paraOutNode->astNode = funcCallExpr; // Add an actual-out parameter node. Vertex paraOutVertex = addVertex(paraOutNode); actualOutParameters[funcDecl].push_back(paraOutVertex); callInfo.outPara.push_back(paraOutVertex); callInfo.isVoid = false; callInfo.returned = paraOutVertex; // Add a CD edge from call node to this actual-out node. addTrueCDEdge(sdgVertex, paraOutVertex); } functionCalls.push_back(callInfo); //funcCallToArgs[funcCallExpr] = argsNodes; } } // Add control dependence edges. addControlDependenceEdges(cfgVerticesToSdgVertices, *cfg, entryVertex); }
void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const { CFGBlocksSet reachable, visited; if (Eng.hasWorkRemaining()) return; const Decl *D = nullptr; CFG *C = nullptr; ParentMap *PM = nullptr; const LocationContext *LC = nullptr; // Iterate over ExplodedGraph for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end(); I != E; ++I) { const ProgramPoint &P = I->getLocation(); LC = P.getLocationContext(); if (!LC->inTopFrame()) continue; if (!D) D = LC->getAnalysisDeclContext()->getDecl(); // Save the CFG if we don't have it already if (!C) C = LC->getAnalysisDeclContext()->getUnoptimizedCFG(); if (!PM) PM = &LC->getParentMap(); if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) { const CFGBlock *CB = BE->getBlock(); reachable.insert(CB->getBlockID()); } } // Bail out if we didn't get the CFG or the ParentMap. if (!D || !C || !PM) return; // Don't do anything for template instantiations. Proving that code // in a template instantiation is unreachable means proving that it is // unreachable in all instantiations. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) if (FD->isTemplateInstantiation()) return; // Find CFGBlocks that were not covered by any node for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) { const CFGBlock *CB = *I; // Check if the block is unreachable if (reachable.count(CB->getBlockID())) continue; // Check if the block is empty (an artificial block) if (isEmptyCFGBlock(CB)) continue; // Find the entry points for this block if (!visited.count(CB->getBlockID())) FindUnreachableEntryPoints(CB, reachable, visited); // This block may have been pruned; check if we still want to report it if (reachable.count(CB->getBlockID())) continue; // Check for false positives if (isInvalidPath(CB, *PM)) continue; // It is good practice to always have a "default" label in a "switch", even // if we should never get there. It can be used to detect errors, for // instance. Unreachable code directly under a "default" label is therefore // likely to be a false positive. if (const Stmt *label = CB->getLabel()) if (label->getStmtClass() == Stmt::DefaultStmtClass) continue; // Special case for __builtin_unreachable. // FIXME: This should be extended to include other unreachable markers, // such as llvm_unreachable. if (!CB->empty()) { bool foundUnreachable = false; for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end(); ci != ce; ++ci) { if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>()) if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable || CE->isBuiltinAssumeFalse(Eng.getContext())) { foundUnreachable = true; break; } } } if (foundUnreachable) continue; } // We found a block that wasn't covered - find the statement to report SourceRange SR; PathDiagnosticLocation DL; SourceLocation SL; if (const Stmt *S = getUnreachableStmt(CB)) { // In macros, 'do {...} while (0)' is often used. Don't warn about the // condition 0 when it is unreachable. if (S->getBeginLoc().isMacroID()) if (const auto *I = dyn_cast<IntegerLiteral>(S)) if (I->getValue() == 0ULL) if (const Stmt *Parent = PM->getParent(S)) if (isa<DoStmt>(Parent)) continue; SR = S->getSourceRange(); DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), LC); SL = DL.asLocation(); if (SR.isInvalid() || !SL.isValid()) continue; } else continue; // Check if the SourceLocation is in a system header const SourceManager &SM = B.getSourceManager(); if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL)) continue; B.EmitBasicReport(D, this, "Unreachable code", "Dead code", "This statement is never executed", DL, SR); } }
void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const { CFGBlocksSet reachable, visited; if (Eng.hasWorkRemaining()) return; CFG *C = 0; ParentMap *PM = 0; // Iterate over ExplodedGraph for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end(); I != E; ++I) { const ProgramPoint &P = I->getLocation(); const LocationContext *LC = P.getLocationContext(); // Save the CFG if we don't have it already if (!C) C = LC->getAnalysisContext()->getUnoptimizedCFG(); if (!PM) PM = &LC->getParentMap(); if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) { const CFGBlock *CB = BE->getBlock(); reachable.insert(CB->getBlockID()); } } // Bail out if we didn't get the CFG or the ParentMap. if (!C || !PM) return; ASTContext &Ctx = B.getContext(); // Find CFGBlocks that were not covered by any node for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) { const CFGBlock *CB = *I; // Check if the block is unreachable if (reachable.count(CB->getBlockID())) continue; // Check if the block is empty (an artificial block) if (isEmptyCFGBlock(CB)) continue; // Find the entry points for this block if (!visited.count(CB->getBlockID())) FindUnreachableEntryPoints(CB, reachable, visited); // This block may have been pruned; check if we still want to report it if (reachable.count(CB->getBlockID())) continue; // Check for false positives if (CB->size() > 0 && isInvalidPath(CB, *PM)) continue; // Special case for __builtin_unreachable. // FIXME: This should be extended to include other unreachable markers, // such as llvm_unreachable. if (!CB->empty()) { CFGElement First = CB->front(); if (const CFGStmt *S = First.getAs<CFGStmt>()) { if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) continue; } } } // We found a block that wasn't covered - find the statement to report SourceRange SR; SourceLocation SL; if (const Stmt *S = getUnreachableStmt(CB)) { SR = S->getSourceRange(); SL = S->getLocStart(); if (SR.isInvalid() || SL.isInvalid()) continue; } else continue; // Check if the SourceLocation is in a system header const SourceManager &SM = B.getSourceManager(); if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL)) continue; B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never" " executed", SL, SR); } }
CFGReverseBlockReachabilityAnalysis::CFGReverseBlockReachabilityAnalysis(const CFG &cfg) : analyzed(cfg.getNumBlockIDs(), false) {}
/// CheckFallThrough - Check that we don't fall off the end of a /// Statement that should return a value. /// /// \returns AlwaysFallThrough iff we always fall off the end of the statement, /// MaybeFallThrough iff we might or might not fall off the end, /// NeverFallThroughOrReturn iff we never fall off the end of the statement or /// return. We assume NeverFallThrough iff we never fall off the end of the /// statement but we may return. We assume that functions not marked noreturn /// will return. static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { CFG *cfg = AC.getCFG(); if (cfg == 0) return UnknownFallThrough; // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. llvm::BitVector live(cfg->getNumBlockIDs()); unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), live); bool AddEHEdges = AC.getAddEHEdges(); if (!AddEHEdges && count != cfg->getNumBlockIDs()) // When there are things remaining dead, and we didn't add EH edges // from CallExprs to the catch clauses, we have to go back and // mark them as live. for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { CFGBlock &b = **I; if (!live[b.getBlockID()]) { if (b.pred_begin() == b.pred_end()) { if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. count += reachable_code::ScanReachableFromBlock(b, live); continue; } } } // Now we know what is live, we check the live precessors of the exit block // and look for fall through paths, being careful to ignore normal returns, // and exceptional paths. bool HasLiveReturn = false; bool HasFakeEdge = false; bool HasPlainEdge = false; bool HasAbnormalEdge = false; for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), E = cfg->getExit().pred_end(); I != E; ++I) { CFGBlock& B = **I; if (!live[B.getBlockID()]) continue; if (B.size() == 0) { if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { HasAbnormalEdge = true; continue; } // A labeled empty statement, or the entry block... HasPlainEdge = true; continue; } Stmt *S = B[B.size()-1]; if (isa<ReturnStmt>(S)) { HasLiveReturn = true; continue; } if (isa<ObjCAtThrowStmt>(S)) { HasFakeEdge = true; continue; } if (isa<CXXThrowExpr>(S)) { HasFakeEdge = true; continue; } if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { if (AS->isMSAsm()) { HasFakeEdge = true; HasLiveReturn = true; continue; } } if (isa<CXXTryStmt>(S)) { HasAbnormalEdge = true; continue; } bool NoReturnEdge = false; if (CallExpr *C = dyn_cast<CallExpr>(S)) { if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) == B.succ_end()) { HasAbnormalEdge = true; continue; } Expr *CEE = C->getCallee()->IgnoreParenCasts(); if (getFunctionExtInfo(CEE->getType()).getNoReturn()) { NoReturnEdge = true; HasFakeEdge = true; } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { ValueDecl *VD = DRE->getDecl(); if (VD->hasAttr<NoReturnAttr>()) { NoReturnEdge = true; HasFakeEdge = true; } } } // FIXME: Remove this hack once temporaries and their destructors are // modeled correctly by the CFG. if (CXXExprWithTemporaries *E = dyn_cast<CXXExprWithTemporaries>(S)) { for (unsigned I = 0, N = E->getNumTemporaries(); I != N; ++I) { const FunctionDecl *FD = E->getTemporary(I)->getDestructor(); if (FD->hasAttr<NoReturnAttr>() || FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) { NoReturnEdge = true; HasFakeEdge = true; break; } } } // FIXME: Add noreturn message sends. if (NoReturnEdge == false) HasPlainEdge = true; } if (!HasPlainEdge) { if (HasLiveReturn) return NeverFallThrough; return NeverFallThroughOrReturn; } if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) return MaybeFallThrough; // This says AlwaysFallThrough for calls to functions that are not marked // noreturn, that don't return. If people would like this warning to be more // accurate, such functions should be marked as noreturn. return AlwaysFallThrough; }