bool printDataflowInfoPass::transfer(const Function& func, const DataflowNode& n, NodeState& state, const vector<Lattice*>& dfInfo) { Dbg::dbg << "-----#############################--------\n"; Dbg::dbg << "Node: ["<<Dbg::escape(n.getNode()->unparseToString())<<" | "<< n.getNode()->class_name()<<"]\n"; // print out all the dataflow facts associated with analysis at this node const /*map <int, NodeFact*>*/vector<NodeFact*> facts = state.getFacts(analysis); int i=0; for(/*map <int, NodeFact*>*/vector<NodeFact*>::const_iterator it = facts.begin(); it!=facts.end(); it++, i++) { //Dbg::dbg << "Fact "<<it->first<<": \n "<<it->second->str(" ")<<endl; Dbg::dbg << "Fact "<<i<<": \n "<<(*it)->str(" ")<<endl; } const vector<Lattice*> dfInfoAbove = state.getLatticeAbove((Analysis*)analysis); const vector<Lattice*> dfInfoBelow = state.getLatticeBelow((Analysis*)analysis); vector<Lattice*>::const_iterator itA, itB; for(itA = dfInfoAbove.begin(), itB = dfInfoBelow.begin(); itA != dfInfoAbove.end() && itB != dfInfoBelow.end(); itA++, itB++) { Dbg::dbg << " Lattice Above "<<*itA<<": \n "<<(*itA)->str(" ")<<endl; Dbg::dbg << " Lattice Below "<<*itB<<": \n "<<(*itB)->str(" ")<<endl; } return dynamic_cast<BoolAndLattice*>(dfInfo[0])->set(true); }
// advances this iterator in the given direction. Forwards if fwDir=true and backwards if fwDir=false. // if pushAllChildren=true, all of the current node's unvisited children (predecessors or successors, // depending on fwDir) are pushed onto remainingNodes void iterator::advance(bool fwDir, bool pushAllChildren) { ROSE_ASSERT(initialized); /*printf(" iterator::advance(%d) remainingNodes.size()=%d\n", fwDir, remainingNodes.size()); cout<<" visited=\n"; for(set<DataflowNode>::iterator it=visited.begin(); it!=visited.end(); it++) cout << " <"<<it->getNode()->class_name()<<" | "<<it->getNode()<<" | "<<it->getNode()->unparseToString()<<">\n";*/ if(remainingNodes.size()>0) { // pop the next CFG node from the front of the list DataflowNode cur = remainingNodes.front(); remainingNodes.pop_front(); if(pushAllChildren) { // find its followers (either successors or predecessors, depending on value of fwDir), push back // those that have not yet been visited vector<DataflowEdge> nextE; if(fwDir) nextE = cur.outEdges(); else nextE = cur.inEdges(); for(vector<DataflowEdge>::iterator it=nextE.begin(); it!=nextE.end(); it++) { DataflowNode nextN((*it).target()/* need to put something here because DataflowNodes don't have a default constructor*/); if(fwDir) nextN = (*it).target(); else nextN = (*it).source(); /*cout << " iterator::advance "<<(fwDir?"descendant":"predecessor")<<": "<< "<"<<nextN.getNode()->class_name()<<" | "<<nextN.getNode()<<" | "<<nextN.getNode()->unparseToString()<<">, "<< "visited="<<(visited.find(nextN) != visited.end())<< " remaining="<<isRemaining(nextN)<<"\n";*/ // if we haven't yet visited this node and don't yet have it on the remainingNodes list if(visited.find(nextN) == visited.end() && !isRemaining(nextN)) { //printf(" pushing back node <%s: 0x%x: %s> visited=%d\n", nextN.getNode()->class_name().c_str(), nextN.getNode(), nextN.getNode()->unparseToString().c_str(), visited.find(nextN)!=visited.end()); remainingNodes.push_back(nextN); } } } // if we still have any nodes left remaining if(remainingNodes.size()>0) { // take the next node from the front of the list and mark it as visited //visited[remainingNodes.front()] = true; visited.insert(remainingNodes.front()); } } }
void TaintAnalysis::genInitState(const Function& func, const DataflowNode& node, const NodeState& state, std::vector<Lattice*>& initLattices, std::vector<NodeFact*>& initFacts) { if (debug) { *debug <<"TaintAnalysis::genInitState(func=" <<func.get_name() <<",\n" <<" node={" <<StringUtility::makeOneLine(node.toString()) <<"},\n" <<" state={" <<StringUtility::makeOneLine(state.str(this, "")) <<"},\n" <<" initLattice[" <<initLattices.size() <<"]={...},\n" <<" initFacts[" <<initFacts.size() <<"]={...})\n"; } map<varID, Lattice*> emptyM; FiniteVarsExprsProductLattice *prodLat = new FiniteVarsExprsProductLattice(new TaintLattice, emptyM, (Lattice*)NULL, ldv_analysis, node, state); assert(prodLat!=NULL); magic_tainted(node.getNode(), prodLat); // certain names are considered to be always tainted initLattices.push_back(prodLat); }
bool transfer(const Function& func, const DataflowNode& n, NodeState& state, const vector<Lattice*>& dfInfo) { printf("saveAllDataflow: node=<%s | %s>\n", n.getNode()->class_name().c_str(), n.getNode()->unparseToString().c_str()); printf(" isSgAddOp(n.getNode()=%p\n", isSgAddOp(n.getNode())); bool modified = false; if(isSgAddOp(n.getNode())) { modified = dynamic_cast<BoolAndLattice*>(dfInfo.at(0))->set(true); modified = dynamic_cast<IntMaxLattice*>(dfInfo.at(1))->incr(1) || modified; } else { //modified = dynamic_cast<BoolAndLattice*>(dfInfo.at(0))->set(false); modified = dynamic_cast<IntMaxLattice*>(dfInfo.at(1))->maximum(0) || modified; } return modified; }
// This will be visited only once? Not sure, better check void analysisStatesToDOT::visit(const Function& func, const DataflowNode& n, NodeState& state) { std::string state_str = state.str( lda, " "); printNode(n, state_str); std::vector < DataflowEdge> outEdges = n.outEdges(); for (unsigned int i = 0; i < outEdges.size(); ++i) { printEdge(outEdges[i]); } }
void FindAllFunctionCalls::visit(const Function& func, const DataflowNode& n, NodeState& state) { SgNode* sgn = n.getNode(); if(analysisDebugLevel>=2){ Dbg::dbg << "FindAllFunctionCalls::visit() sgn="<<sgn<<"["<<sgn->class_name()<<" | "<<Dbg::escape(sgn->unparseToString())<<"]"<<endl; } // If this is a function call, find the function that is being called and if it is // in funcsToFind, record the call in funcCalls if(isSgFunctionCallExp(sgn)) { for(set<Function>::const_iterator func=funcsToFind.begin(); func!=funcsToFind.end(); func++) { if((*func).get_declaration() == isSgFunctionCallExp(sgn)->getAssociatedFunctionDeclaration()) { funcCalls[*func].insert(n); break; } } } }
void evaluateAnalysisStates::visit(const Function& func, const DataflowNode& n, NodeState& state) { SgFunctionCallExp *fnCall = isSgFunctionCallExp(n.getNode()); if (!fnCall) return; if (!fnCall->getAssociatedFunctionSymbol()) return; string funcName = fnCall->getAssociatedFunctionSymbol()->get_name().getString(); if (funcName.find("testFunc") == string::npos) return; FiniteVarsExprsProductLattice *lat = dynamic_cast<FiniteVarsExprsProductLattice *>(state.getLatticeAbove(div)[0]); cout << indent << "Lattice before call to " << funcName << ": " << lat->str() << endl; set<varID> allVars = lat->getAllVars(); for (set<varID>::iterator i = allVars.begin(); i != allVars.end(); ++i) { string name = i->str(); cout << "Variable " << name << " "; if (expectations[funcName].find(name) == expectations[funcName].end()) { cout << "unspecified" << endl; continue; } Lattice *got = lat->getVarLattice(*i); ROSE_ASSERT(got); if (expectations[funcName][name] != got) { cout << "mismatched: " << got->str() << " was not the expected " << expectations[funcName][name].str(); numFails++; } else { cout << "matched"; numPass++; } cout << endl; } }
void InitDataflowState::visit(const Function& func, const DataflowNode& n, NodeState& state) { SgNode* sgn = n.getNode(); if(analysisDebugLevel>=2) Dbg::dbg << "InitDataflowState::visit() sgn="<<sgn<<"["<<sgn->class_name()<<" | "<<Dbg::escape(sgn->unparseToString())<<"], dfAnalysis="<<dfAnalysis<<endl; // generate a new initial state for this node vector<Lattice*> initLats; vector<NodeFact*> initFacts; dfAnalysis->genInitState(func, n, state, initLats, initFacts); /*if(analysisDebugLevel>=2){ int i=0; for(vector<Lattice*>::iterator l=initLats.begin(); l!=initLats.end(); l++, i++) Dbg::dbg << "Lattice "<<i<<": "<<(*l)->str(" ")<<endl; i=0; for(vector<NodeFact*>::iterator f=initFacts.begin(); f!=initFacts.end(); f++, i++) Dbg::dbg << "Lattice "<<i<<": "<<(*f)->str(" ")<<endl; }*/ //Dbg::dbg << "InitDataflowState::visit() calling state.setLattices()"<<endl; state.setLattices((Analysis*)dfAnalysis, initLats); state.setFacts((Analysis*)dfAnalysis, initFacts); if(analysisDebugLevel>=2){ Dbg::dbg << " state="<<state.str((Analysis*)dfAnalysis, " ")<<endl; } /*vector<Lattice*> initState = dfAnalysis->genInitState(func, n, state); Dbg::dbg << "InitDataflowState::visit() 1"<<endl; for(int i=0; i<initState.size(); i++) { Dbg::dbg << " i="<<i<<", initState[i]="<<initState[i]->str("")<<endl; state.addLattice((Analysis*)dfAnalysis, i, initState[i]); Dbg::dbg << " state->getLatticeAbove((Analysis*)dfAnalysis).size()="<<state.getLatticeAbove((Analysis*)dfAnalysis).size()<<endl, ); //Dbg::dbg << printf(" state->getLatticeBelow((Analysis*)dfAnalysis).size()="<<state.getLatticeBelow((Analysis*)dfAnalysis).size()<<endl; }*/ //const vector<Lattice*>& masterLatBel = state.getLatticeBelow((Analysis*)dfAnalysis); //printf(" creator=%p, state=%p, masterLatBel.size()=%d\n", (Analysis*)dfAnalysis, &state, masterLatBel.size()); }
void analysisStatesToDOT::printNode(const DataflowNode& n, std::string state_string) { std::string id = n.id(); // node id std::string nodeColor = "black"; if (isSgStatement(n.getNode())) nodeColor = "blue"; else if (isSgExpression(n.getNode())) nodeColor = "green"; else if (isSgInitializedName(n.getNode())) nodeColor = "red"; // node_id [label="", color="", style=""] (*ostr) << id << " [label=\"" << escapeString(n.toString()) <<"\\n" << escapeString (state_string) << "\", color=\"" << nodeColor << "\", style=\"" << (n.isInteresting()? "solid" : "dotted") << "\"];\n"; }
void MergeAllReturnStates::visit(const Function& func, const DataflowNode& n, NodeState& state) { SgNode* sgn = n.getNode(); if(analysisDebugLevel>=1) Dbg::dbg << "MergeAllReturnStates::visit() func="<<func.get_name().getString()<<"() sgn="<<sgn<<"["<<Dbg::escape(sgn->unparseToString())<<" | "<<sgn->class_name()<<"]\n"; //Dbg::dbg << "visit {{{: modified="<<modified<<endl; // If this is an explicit return statement if(isSgReturnStmt(sgn)) { if(analysisDebugLevel>=1) Dbg::dbg << "MergeAllReturnStates::visit() isSgReturnStmt(sgn)->get_expression()="<<isSgReturnStmt(sgn)->get_expression()<<"["<<Dbg::escape(isSgReturnStmt(sgn)->get_expression()->unparseToString())<<" | "<<isSgReturnStmt(sgn)->get_expression()->class_name()<<"]\n"; ROSE_ASSERT(NodeState::getNodeStates(n).size()==1); NodeState* state = *(NodeState::getNodeStates(n).begin()); // Incorporate the entire dataflow state at the return statement if(analysisDebugLevel>=1) Dbg::dbg << " Merging dataflow state at return statement\n"; modified = mergeLats(mergedLatsRetStmt, state->getLatticeAbove(analysis)) || modified; // Incorporate just the portion of the dataflow state that corresponds to the value being returned, // assuming that any information is available vector<Lattice*> exprLats; for(vector<Lattice*>::const_iterator l=state->getLatticeAbove(analysis).begin(); l!=state->getLatticeAbove(analysis).end(); l++) exprLats.push_back((*l)->project(isSgReturnStmt(sgn)->get_expression())); if(analysisDebugLevel>=1) Dbg::dbg << " Merging dataflow state of return value\n"; modified = mergeLats(mergedLatsRetVal, exprLats) || modified; } // If this is the end of a function, which is an implicit return that has no return value else if(isSgFunctionDefinition(sgn)) { if(analysisDebugLevel>=1) Dbg::dbg << "MergeAllReturnStates::visit() isSgFunctionDefinition\n"; ROSE_ASSERT(NodeState::getNodeStates(n).size()==1); NodeState* state = *(NodeState::getNodeStates(n).begin()); // Incorporate the entire dataflow state at the implicit return statement modified = mergeLats(mergedLatsRetStmt, state->getLatticeAbove(analysis)) || modified; } //Dbg::dbg << "visit >>>: modified="<<modified<<endl; }
void visit(const Function& func, const DataflowNode& n, NodeState& state) { printf("checkAllDataflow: node=<%s | %s>\n", n.getNode()->class_name().c_str(), n.getNode()->unparseToString().c_str()); /*stringWrapper* s0 = (stringWrapper*)state.getFact(creator, 0); stringWrapper* s1 = (stringWrapper*)state.getFact(creator, 1); printf(" fact=<%p | %p>\n", s0, s1); printf(" fact=<%s | %s>\n", s0->myStr.c_str(), s1->myStr.c_str());* / if(n.getNode()->class_name() != s0->myStr.c_str()) { printf("ERROR in checkAllDataflow: Expected class name \"%s\" but the saved class name is \"%s\"\n", n.getNode()->class_name().c_str(), s0->myStr.c_str()); numFails++; } if(n.getNode()->unparseToString() != s1->myStr.c_str()) { printf("ERROR in checkAllDataflow: Expected class name \"%s\" but the saved class name is \"%s\"\n", n.getNode()->unparseToString().c_str(), s0->myStr.c_str()); numFails++; }*/ printf(" lattice0 = %s\n", state.getLatticeBelow(creator, 0)->str().c_str()); printf(" lattice1 = %s\n", state.getLatticeBelow(creator, 1)->str().c_str()); }
// Splits the given dataflow analysis partition into several partitions, one for each given checkpoint. // The partition origA will be assigned the last checkpoint in partitionChkpts. // If newSplit==true, this split operation creates a new split within origA's current split and place // the newly-generated partitions into this split. // If newSplit==false, the newly-generated partitions will be added to origA's current split. // If newPartActive==true, the newly-generated partitions will be made initially active. If not, // they will start out in joined status. // Returns the set of newly-created partitions. set<IntraPartitionDataflow*> PartitionedAnalysis::split(IntraPartitionDataflow* origA, vector<IntraPartitionDataflowCheckpoint*> partitionChkpts, const Function& func, NodeState* fState, bool newSplit, bool newPartActive) { /*printf("PartitionedAnalysis::split() origA=%p\n", origA); for(vector<IntraPartitionDataflowCheckpoint*>::iterator it = partitionChkpts.begin(); it!=partitionChkpts.end(); it++) { printf(" chkpt=%s\n", (*it)->str(" ").c_str()); }*/ ROSE_ASSERT(partitionChkpts.size()>0); if(analysisDebugLevel>=1) { printf("@ SPLIT @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); printf("PartitionedAnalysis::split() before: activeParts.size()=%d\n", activeParts.size()); } // Only partitions that are either active or joined may call split. Joined partitions may do so during the joining process, // which can result in the creation of new partitions. ROSE_ASSERT(activeParts.find(origA) != activeParts.end() || joinParts.find(origA) != joinParts.end()); if(analysisDebugLevel>=1) if(origA->partitionCond != NULL) cout << "origA->partitionCond = "<<origA->partitionCond->str()<<"\n"; partSplit* split=NULL; if(newSplit) split = new partSplit(origA); else split = *(parts2splits[origA].rbegin()); if(analysisDebugLevel>=1) cout << "split = "<<split->str()<<", partitionChkpts.size()="<<partitionChkpts.size()<<"\n"; fflush(stdout); set<IntraPartitionDataflow*> newParts; // Generate the new analysis partitions. The last checkpoint goes to the master // partition and we create fresh partitions for the other checkpoints for(vector<IntraPartitionDataflowCheckpoint*>::iterator it = partitionChkpts.begin(); it!=partitionChkpts.end(); ) { IntraPartitionDataflowCheckpoint* chkpt = *it; IntraPartitionDataflow* curPartA; if(analysisDebugLevel>=1) { cout << " chkpt->partitionCond="<<chkpt->partitionCond<<"\n"; fflush(stdout); } it++; if(it != partitionChkpts.end()) { curPartA = origA->copy(); split->addChild(curPartA); newParts.insert(curPartA); parts2chkpts[curPartA] = chkpt; // Create a splits list for this newly-created partition // The splits list only contains the split (which may be newly-created or a copy of parts2splits[origA]) // since it will cease to exist after the next successful join of split list<partSplit*> splitsList; splitsList.push_back(split); parts2splits[curPartA] = splitsList; // Set the current partition's logical condition (can't AND it because the variables involved in // the condition may have changed between the two split points) curPartA->partitionCond = chkpt->partitionCond; /*if(origA->partitionCond != NULL) curPartA->partitionCond->andUpd(*(origA->partitionCond));*/ if(analysisDebugLevel>=1) //{ printf(" Creating analysis partition %p (master = %p), condition = %s\n", curPartA, origA, curPartA->partitionCond->str("").c_str()); } { printf(" Creating analysis partition %p (master = %p)\n", curPartA, origA); } // create a copy of the original partition's dataflow state for the new partition partitionDFAnalysisState pdfas(origA, curPartA); pdfas.runAnalysis(func, fState); // add the newly-created partition to the list of active partitions if(newPartActive) activeParts.insert(curPartA); else joinParts.insert(curPartA); } else { //// AND this the first partition's new logical condition to the original partition's condition // set the first partition's logical condition (can't AND it because the variables involved in the condition // may have changed between the two split points) /*printf("origA->partitionCond=%p\n", origA->partitionCond); printf(" partitionChkpts[0]=%s\n", partitionChkpts[0]->str(" ").c_str());*/ //if(parts2chkpts[origA] != NULL) /*if(origA->partitionCond != NULL) { //parts2chkpts[origA]->partitionCond->andUpd(*(partitionChkpts[0]->partitionCond)); origA->partitionCond->andUpd(*(partitionChkpts[0]->partitionCond)); if(parts2chkpts[origA]) delete parts2chkpts[origA]; parts2chkpts[origA] = partitionChkpts[0]; // we already have a checkpoint object for the origA partition, so we can delete this new checkpoint // and its internals (i.e. the partitionCond object) //delete partitionChkpts[0]; } else {*/ origA->partitionCond = chkpt->partitionCond; // Delete the previous checkpoint, assuming that one exists AND we're not reusing the // old checkpoint as the new checkpoint if(parts2chkpts[origA] && parts2chkpts[origA]!=chkpt) delete parts2chkpts[origA]; parts2chkpts[origA] = chkpt; curPartA = origA; //} /*if(analysisDebugLevel>=1) { printf(" Master partition %p, condition = %s\n", origA, origA->partitionCond->str("").c_str()); }*/ } if(analysisDebugLevel>=1) { cout << "Updating current partition's dataflow state, parts2chkpts[curPartA]->joinNodes.size()="<<parts2chkpts[curPartA]->joinNodes.size()<<"\n"; cout << " curPartA->partitionCond="<<curPartA->partitionCond<<"\n"; fflush(stdout); } // ----------------------------------------------------------------------------------------------- // Update the current partition's current dataflow state (state at the nodes in its joinNodes set) // with its new partition condition // joinNodes /* cout << "parts2chkpts[curPartA]->joinNodes.size()=" << parts2chkpts[curPartA]->joinNodes.size() << "\n"; for(set<DataflowNode>::iterator itJN=parts2chkpts[curPartA]->joinNodes.begin(); itJN!=parts2chkpts[curPartA]->joinNodes.end(); itJN++) cout << " itJN = "<<(*itJN).getNode()->unparseToString()<<"\n";*/ for(set<DataflowNode>::iterator itJN=parts2chkpts[curPartA]->joinNodes.begin(); itJN!=parts2chkpts[curPartA]->joinNodes.end(); ) { DataflowNode n = *itJN; if(analysisDebugLevel>=1) { cout << " joinNode "<<n.getNode()->unparseToString()<<"\n"; fflush(stdout); } const vector<NodeState*> nodeStates = NodeState::getNodeStates(n); //for(vector<NodeState*>::const_iterator itS = nodeStates.begin(); itS!=nodeStates.end(); ) vector<NodeState*>::const_iterator itS = nodeStates.begin(); { NodeState* state = *itS; Analysis* a = curPartA; curPartA->initDFfromPartCond(func, n, *state, state->getLatticeBelow(a), state->getFacts(a), curPartA->partitionCond); } itJN++; } // Current Node if(parts2chkpts[curPartA]->curNode) { DataflowNode n = *(parts2chkpts[curPartA]->curNode); if(analysisDebugLevel>=1) cout << " curNode "<<n.getNode()->unparseToString()<<"\n"; const vector<NodeState*> nodeStates = NodeState::getNodeStates(n); //for(vector<NodeState*>::const_iterator itS = nodeStates.begin(); itS!=nodeStates.end(); ) vector<NodeState*>::const_iterator itS = nodeStates.begin(); { NodeState* state = *itS; Analysis* a = curPartA; /*ConstrGraph* cg = dynamic_cast<ConstrGraph*>(state->getLatticeBelow(a).front()); cout << "Pre-initDFfromPartCond CG="<<cg->str()<<"\n";*/ curPartA->initDFfromPartCond(func, n, *state, state->getLatticeBelow(a), state->getFacts(a), curPartA->partitionCond); } } } //printf(" partitionChkpts[0]=%s\n", partitionChkpts[0]->str(" ").c_str()); //printf(" parts2chkpts[origA]=%s\n", parts2chkpts[origA]->str(" ").c_str()); // add the new split to the original partition's list of splits if(newSplit) parts2splits[origA].push_back(split); /*for(set<IntraPartitionDataflow*>::iterator it=split->splitSet.begin(); it!=split->splitSet.end(); it++) printf(" partition %p, partitionCond=%p\n", *it, parts2chkpts[*it]->partitionCond);*/ if(analysisDebugLevel>=1) { printf("PartitionedAnalysis::split() after: activeParts.size()=%d\n", activeParts.size()); printf("@ SPLIT @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); } if(analysisDebugLevel>=1) cout << "newParts.size()=="<<newParts.size()<<"\n"; return newParts; }
bool TaintAnalysis::transfer(const Function& func, const DataflowNode& node_, NodeState& state, const std::vector<Lattice*>& dfInfo) { static size_t ncalls = 0; if (debug) { *debug <<"TaintAnalysis::transfer-" <<++ncalls <<"(func=" <<func.get_name() <<",\n" <<" node={" <<StringUtility::makeOneLine(node_.toString()) <<"},\n" <<" state={" <<state.str(this, " ") <<",\n" <<" dfInfo[" <<dfInfo.size() <<"]={...})\n"; } SgNode *node = node_.getNode(); assert(!dfInfo.empty()); FiniteVarsExprsProductLattice *prodLat = dynamic_cast<FiniteVarsExprsProductLattice*>(dfInfo.front()); bool modified = magic_tainted(node, prodLat); // some values are automatically tainted based on their name // Process AST nodes that transfer taintedness. Most of these operations have one or more inputs from which a result // is always calculated the same way. So we just gather up the inputs and do the calculation at the very end of this // function. The other operations are handled individually within their "if" bodies. TaintLattice *result = NULL; // result pointer into the taint lattice std::vector<TaintLattice*> inputs; // input pointers into the taint lattice if (isSgAssignInitializer(node)) { // as in "int a = b" SgAssignInitializer *xop = isSgAssignInitializer(node); TaintLattice *in1 = dynamic_cast<TaintLattice*>(prodLat->getVarLattice(SgExpr2Var(xop->get_operand()))); inputs.push_back(in1); } else if (isSgAggregateInitializer(node)) { // as in "int a[1] = {b}" SgAggregateInitializer *xop = isSgAggregateInitializer(node); const SgExpressionPtrList &exprs = xop->get_initializers()->get_expressions(); for (size_t i=0; i<exprs.size(); ++i) { varID in_id = SgExpr2Var(exprs[i]); TaintLattice *in = dynamic_cast<TaintLattice*>(prodLat->getVarLattice(in_id)); inputs.push_back(in); } } else if (isSgInitializedName(node)) { SgInitializedName *xop = isSgInitializedName(node); if (xop->get_initializer()) { varID in1_id = SgExpr2Var(xop->get_initializer()); TaintLattice *in1 = dynamic_cast<TaintLattice*>(prodLat->getVarLattice(in1_id)); inputs.push_back(in1); } } else if (isSgValueExp(node)) { // numeric and character constants SgValueExp *xop = isSgValueExp(node); result = dynamic_cast<TaintLattice*>(prodLat->getVarLattice(SgExpr2Var(xop))); if (result) modified = result->set_vertex(TaintLattice::VERTEX_UNTAINTED); } else if (isSgAddressOfOp(node)) { // as in "&x". The result taintedness has nothing to do with the value in x. /*void*/ } else if (isSgBinaryOp(node)) { // as in "a + b" SgBinaryOp *xop = isSgBinaryOp(node); varID in1_id = SgExpr2Var(isSgExpression(xop->get_lhs_operand())); TaintLattice *in1 = dynamic_cast<TaintLattice*>(prodLat->getVarLattice(in1_id)); inputs.push_back(in1); varID in2_id = SgExpr2Var(isSgExpression(xop->get_rhs_operand())); TaintLattice *in2 = dynamic_cast<TaintLattice*>(prodLat->getVarLattice(in2_id)); inputs.push_back(in2); if (isSgAssignOp(node)) { // copy the rhs lattice to the lhs lattice (as well as the entire '=' expression result) assert(in1 && in2); modified = in1->meetUpdate(in2); } } else if (isSgUnaryOp(node)) { // as in "-a" SgUnaryOp *xop = isSgUnaryOp(node); varID in1_id = SgExpr2Var(xop->get_operand()); TaintLattice *in1 = dynamic_cast<TaintLattice*>(prodLat->getVarLattice(in1_id)); inputs.push_back(in1); } else if (isSgReturnStmt(node)) { // as in "return a". The result will always be dead, so we're just doing this to get some debugging output. Most // of our test inputs are functions, and the test examines the function's returned taintedness. SgReturnStmt *xop = isSgReturnStmt(node); varID in1_id = SgExpr2Var(xop->get_expression()); TaintLattice *in1 = dynamic_cast<TaintLattice*>(prodLat->getVarLattice(in1_id)); inputs.push_back(in1); } // Update the result lattice (unless dead) with the inputs (unless dead) by using the meedUpdate() method. All this // means is that the new result will be the maximum of the old result and all inputs, where "maximum" is defined such // that "tainted" is greater than "untainted" (and both of them are greater than bottom/unknown). for (size_t i=0; i<inputs.size(); ++i) if (debug) *debug <<"TaintAnalysis::transfer: input " <<(i+1) <<" is " <<lattice_info(inputs[i]) <<"\n"; if (!result && varID::isValidVarExp(node)) { varID result_id(node); // NOTE: constructor doesn't handle all SgExpression nodes, thus the next "if" result = dynamic_cast<TaintLattice*>(prodLat->getVarLattice(result_id)); } if (!result && isSgExpression(node)) { varID result_id = SgExpr2Var(isSgExpression(node)); result = dynamic_cast<TaintLattice*>(prodLat->getVarLattice(result_id)); } if (result) { for (size_t i=0; i<inputs.size(); ++i) { if (inputs[i]) modified = result->meetUpdate(inputs[i]) || modified; } } if (debug) *debug <<"TaintAnalysis::transfer: result is " <<lattice_info(result) <<(modified?" (modified)":" (not modified)") <<"\n"; return modified; }
// The transfer function that is applied to SgFunctionCallExp nodes to perform the appropriate state transfers // fw - =true if this is a forward analysis and =false if this is a backward analysis // n - the dataflow node that is being processed // state - The NodeState object that describes the dataflow state immediately before (if fw=true) or immediately after // (if fw=false) the SgFunctionCallExp node, as established by earlier analysis passes // dfInfo - The Lattices that this transfer function operates on. The function propagates them // to the calling function and overwrites them with the dataflow result of calling this function. // retState - Pointer reference to a Lattice* vector that will be assigned to point to the lattices of // the function call's return value. The callee may not modify these lattices. // Returns true if any of the input lattices changed as a result of the transfer function and // false otherwise. bool ContextInsensitiveInterProceduralDataflow::transfer( const Function& func, const DataflowNode& n, NodeState& state, const vector<Lattice*>& dfInfo, vector<Lattice*>** retState, bool fw) { bool modified = false; SgFunctionCallExp* call = isSgFunctionCallExp(n.getNode()); Function callee(call); ROSE_ASSERT(call); if(analysisDebugLevel > 0) Dbg::dbg << "ContextInsensitiveInterProceduralDataflow::transfer "<<func.get_name().getString()<<"()=>"<<callee.get_name().getString()<<"()\n"; if(callee.get_definition()) { FunctionState* funcS = FunctionState::getDefinedFuncState(callee); // The lattices before the function (forward: before=above, after=below; backward: before=below, after=above) const vector<Lattice*>* funcLatticesBefore; if(fw) funcLatticesBefore = &(funcS->state.getLatticeAbove((Analysis*)intraAnalysis)); else funcLatticesBefore = &(funcS->state.getLatticeBelow((Analysis*)intraAnalysis)); //if(analysisDebugLevel > 0) // printf(" dfInfo.size()=%d, funcLatticesBefore->size()=%d, this=%p\n", dfInfo.size(), funcLatticesBefore->size(), this); // Update the function's entry/exit state with the caller's state at the call site vector<Lattice*>::const_iterator itCalleeBefore, itCallerBefore; for(itCallerBefore = dfInfo.begin(), itCalleeBefore = funcLatticesBefore->begin(); itCallerBefore!=dfInfo.end() && itCalleeBefore!=funcLatticesBefore->end(); itCallerBefore++, itCalleeBefore++) { Lattice* calleeL = *itCalleeBefore; Lattice* callerL = *itCallerBefore; if(analysisDebugLevel>=1) { Dbg::dbg << " callerL=["<<calleeL<<"] "<<callerL->str(" ")<<endl; Dbg::dbg << " Before calleeL=["<<calleeL<<"] "<<calleeL->str(" ")<<endl; } // Create a copy of the current lattice, remapped for the called function's variables Lattice* remappedL = callerL->copy(); map<varID, varID> argParamMap; FunctionState::setArgParamMap(call, argParamMap); /*Dbg::dbg << "#argParamMap="<<argParamMap.size()<<endl; for(map<varID, varID>::iterator it = argParamMap.begin(); it!=argParamMap.end(); it++) { printf("argParamMap[%s] = %s \n", it->first.str().c_str(), it->second.str().c_str()); }*/ remappedL->remapVars(argParamMap, callee); Dbg::dbg << " remappedL=["<<calleeL<<"] "<<remappedL->str(" ")<<endl; // update the callee's Lattice with the new information at the call site modified = calleeL->meetUpdate(remappedL) || modified; if(analysisDebugLevel>=1) Dbg::dbg << " After modified = "<<modified << "calleeL=["<<calleeL<<"] "<<calleeL->str(" ")<<endl; //!!! delete remappedL; } // If this resulted in the dataflow information before the callee changing, add it to the remaining list. if(modified) { if(analysisDebugLevel > 0) Dbg::dbg << "ContextInsensitiveInterProceduralDataflow::transfer Incoming Dataflow info modified\n"; // Record that the callee function needs to be re-analyzed because of new information from the caller TraverseCallGraphDataflow::addToRemaining(getFunc(callee)); remainingDueToCallers.insert(getFunc(callee)); } // The lattices after the function (forward: before=above, after=below; backward: before=below, after=above). const vector<Lattice*>* funcLatticesAfter; if(fw) funcLatticesAfter = &(funcS->state.getLatticeBelow((Analysis*)intraAnalysis)); else funcLatticesAfter = &(funcS->state.getLatticeAbove((Analysis*)intraAnalysis)); //Dbg::dbg << " funcLatticesAfter->size()="<<funcLatticesAfter->size()<<endl; if(analysisDebugLevel>=1) Dbg::dbg << " ----%%%%%%%%%%%%%%%%%%%%---------\n"; // Transfer the result of the function call into the dfInfo Lattices. vector<Lattice*>::const_iterator itCalleeAfter, itCallerAfter; for(itCallerAfter = dfInfo.begin(), itCalleeAfter = funcLatticesAfter->begin(); itCallerAfter!=dfInfo.end() && itCalleeAfter!=funcLatticesAfter->end(); itCallerAfter++, itCalleeAfter++) { Lattice* callerL = *itCallerAfter; Lattice* calleeL = *itCalleeAfter; //Dbg::dbg << " calleeL-after=["<<calleeL<<"] "<<calleeL->str(" ")<<endl; // Create a copy of the current lattice, remapped for the callee function's variables Lattice* remappedL = calleeL->copy(); if(analysisDebugLevel>=1) Dbg::dbg << " remappedL-after=["<<remappedL<<"] "<<calleeL->str(" ")<<endl << remappedL->str(" ")<<endl; map<varID, varID> paramArgByRefMap; FunctionState::setParamArgByRefMap(call, paramArgByRefMap); /*Dbg::dbg << "#paramArgByRefMap="<<paramArgByRefMap.size()<<endl; for(map<varID, varID>::iterator it = paramArgByRefMap.begin(); it!=paramArgByRefMap.end(); it++) { Dbg::dbg << "paramArgByRefMap["<<it->first.str()<<"] = "<<it->second.str()<<endl; */ remappedL->remapVars(paramArgByRefMap, func); //Dbg::dbg << " callerL-after=["<<callerL<<"] "<<callerL->str(" ")<<endl; Dbg::dbg << " +remappedL-after=["<<remappedL<<"] "<<remappedL->str(" ")<<endl; // update the caller's Lattice with the new information at the call site callerL->incorporateVars(remappedL); if(analysisDebugLevel>=1) Dbg::dbg << " ==> callerL-after=["<<callerL<<"] "<<callerL->str(" ")<<endl; //Dbg::dbg << " calleeL-after=["<<calleeL<<"] "<<calleeL->str(" ")<<endl; modified = true; //!!! delete remappedL; } // Point retState to the lattices of the function's return values *retState = &(funcS->retState.getLatticeBelowMod((Analysis*)intraAnalysis)); /*Dbg::dbg << " retState="<<retState<<endl; for(vector<Lattice*>::iterator l=(*retState)->begin(); l!=(*retState)->end(); l++) Dbg::dbg << " "<<(*l)->str(" ")<<endl;*/ } // Don't do anything for functions with no definitions else { } return modified; }
// Propagates the dataflow info from the current node's NodeState (curNodeState) to the next node's // NodeState (nextNodeState). // Returns true if the next node's meet state is modified and false otherwise. bool IntraUniDirectionalDataflow::propagateStateToNextNode( const vector<Lattice*>& curNodeState, DataflowNode curNode, int curNodeIndex, const vector<Lattice*>& nextNodeState, DataflowNode nextNode) { bool modified = false; vector<Lattice*>::const_iterator itC, itN; if(analysisDebugLevel>=1){ Dbg::dbg << "\n Propagating to Next Node: "<<nextNode.getNode()<<"["<<nextNode.getNode()->class_name()<<" | "<<Dbg::escape(nextNode.getNode()->unparseToString())<<"]"<<endl; int j; for(j=0, itC = curNodeState.begin(); itC != curNodeState.end(); itC++, j++) Dbg::dbg << " Current node: Lattice "<<j<<": \n "<<(*itC)->str(" ")<<endl; for(j=0, itN = nextNodeState.begin(); itN != nextNodeState.end(); itN++, j++) Dbg::dbg << " Next/Descendant node: Lattice before propagation "<<j<<": \n "<<(*itN)->str(" ")<<endl; } // Update forward info above nextNode from the forward info below curNode. // Compute the meet of the dataflow information along the curNode->nextNode edge with the // next node's current state one Lattice at a time and save the result above the next node. for(itC = curNodeState.begin(), itN = nextNodeState.begin(); itC != curNodeState.end() && itN != nextNodeState.end(); itC++, itN++) { // Finite Lattices can use the regular meet operator, while infinite Lattices // must also perform widening to ensure convergence. if((*itN)->finiteLattice()) { if(analysisDebugLevel>=1) Dbg::dbg << " Finite lattice: using regular meetUpdate from current'lattic into next node's lattice... "<<endl; modified = (*itN)->meetUpdate(*itC) || modified; } else { //InfiniteLattice* meetResult = (InfiniteLattice*)itN->second->meet(itC->second); InfiniteLattice* meetResult = dynamic_cast<InfiniteLattice*>((*itN)->copy()); Dbg::dbg << " *itN: " << dynamic_cast<InfiniteLattice*>(*itN)->str(" ") << endl; Dbg::dbg << " *itC: " << dynamic_cast<InfiniteLattice*>(*itC)->str(" ") << endl; meetResult->meetUpdate(*itC); Dbg::dbg << " meetResult: " << meetResult->str(" ") << endl; // Widen the resulting meet modified = dynamic_cast<InfiniteLattice*>(*itN)->widenUpdate(meetResult); delete meetResult; } } if(analysisDebugLevel>=1) { if(modified) { Dbg::dbg << " Next node's lattice *modified* by the propagation. "<<endl; int j=0; for(itN = nextNodeState.begin(); itN != nextNodeState.end(); itN++, j++) { Dbg::dbg << " Modified lattice "<<j<<": \n "<<(*itN)->str(" ")<<endl; } } else Dbg::dbg << " Next node's lattice is *unchanged* by the propagation. "<<endl; } return modified; }