// printTypesForNode --prints all the types for the given NodeValue, without a newline // (meant to be called as a helper) static void printTypesForNode(llvm::raw_ostream &O, NodeValue &NV) { DSNode *N = NV.getNode(); if (N->isNodeCompletelyFolded()) { O << "Folded"; } // Go through all the types, and just dump them. // FIXME: Lifted from Printer.cpp, probably should be shared bool firstType = true; if (N->type_begin() != N->type_end()) for (DSNode::TyMapTy::const_iterator ii = N->type_begin(), ee = N->type_end(); ii != ee; ++ii) { if (!firstType) O << "::"; firstType = false; O << ii->first << ":"; if (ii->second) { bool first = true; for (svset<Type*>::const_iterator ni = ii->second->begin(), ne = ii->second->end(); ni != ne; ++ni) { if (!first) O << "|"; Type * t = *ni; t->print (O); first = false; } } else O << "VOID"; } else O << "VOID"; if (N->isArrayNode()) O << "Array"; }
// // Method: getUnsafeAllocsFromABC() // // Description: // Find all memory objects that are both allocated on the stack and are not // proven to be indexed in a type-safe manner according to the static array // bounds checking pass. // // Notes: // This method saves its results be remembering the set of DSNodes which are // both on the stack and potentially indexed in a type-unsafe manner. // // FIXME: // This method only considers unsafe GEP instructions; it does not consider // unsafe call instructions or other instructions deemed unsafe by the array // bounds checking pass. // void ConvertUnsafeAllocas::getUnsafeAllocsFromABC(Module & M) { UnsafeAllocaNodeListBuilder Builder(budsPass, unsafeAllocaNodes); Builder.visit(M); #if 0 // Haohui: Disable it right now since nobody using the code std::map<BasicBlock *,std::set<Instruction*>*> UnsafeGEPMap= abcPass->UnsafeGetElemPtrs; std::map<BasicBlock *,std::set<Instruction*>*>::const_iterator bCurrent = UnsafeGEPMap.begin(), bEnd = UnsafeGEPMap.end(); for (; bCurrent != bEnd; ++bCurrent) { std::set<Instruction *> * UnsafeGetElemPtrs = bCurrent->second; std::set<Instruction *>::const_iterator iCurrent = UnsafeGetElemPtrs->begin(), iEnd = UnsafeGetElemPtrs->end(); for (; iCurrent != iEnd; ++iCurrent) { if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(*iCurrent)) { Value *pointerOperand = GEP->getPointerOperand(); DSGraph * TDG = budsPass->getDSGraph(*(GEP->getParent()->getParent())); DSNode *DSN = TDG->getNodeForValue(pointerOperand).getNode(); //FIXME DO we really need this ? markReachableAllocas(DSN); if (DSN && DSN->isAllocaNode() && !DSN->isNodeCompletelyFolded()) { unsafeAllocaNodes.push_back(DSN); } } else { //call instruction add the corresponding *iCurrent->dump(); //FIXME abort(); } } } #endif }
void visitGetElementPtrInst(GetElementPtrInst &GEP) { Value *pointerOperand = GEP.getPointerOperand(); DSGraph * TDG = budsPass->getDSGraph(*(GEP.getParent()->getParent())); DSNode *DSN = TDG->getNodeForValue(pointerOperand).getNode(); //FIXME DO we really need this ? markReachableAllocas(DSN); if (DSN && DSN->isAllocaNode() && !DSN->isNodeCompletelyFolded()) { unsafeAllocaNodes.push_back(DSN); } }
bool DSGraphStats::isNodeForValueUntyped(Value *V, unsigned Offset, const Function *F) { DSNodeHandle NH = getNodeHandleForValue(V); if(!NH.getNode()){ return true; } else { DSNode *N = NH.getNode(); if (N->isNodeCompletelyFolded()){ ++NumFoldedAccess; return true; } if ( N->isExternalNode()){ ++NumExternalAccesses; return true; } if ( N->isIncompleteNode()){ ++NumIncompleteAccesses; return true; } if (N->isUnknownNode()){ ++NumUnknownAccesses; return true; } if (N->isIntToPtrNode()){ ++NumI2PAccesses; return true; } // it is a complete node, now check how many types are present int count = 0; unsigned offset = NH.getOffset() + Offset; if (N->type_begin() != N->type_end()) for (DSNode::TyMapTy::const_iterator ii = N->type_begin(), ee = N->type_end(); ii != ee; ++ii) { if(ii->first != offset) continue; count += ii->second->size(); } if (count ==0) ++NumTypeCount0Accesses; else if(count == 1) ++NumTypeCount1Accesses; else if(count == 2) ++NumTypeCount2Accesses; else if(count == 3) ++NumTypeCount3Accesses; else ++NumTypeCount4Accesses; DEBUG(assert(TS->isTypeSafe(V,F))); } return false; }
// // TODO // template<class dsa> bool TypeSafety<dsa>::isFieldDisjoint (const GlobalValue * V, unsigned offset) { // // Get the DSNode for the specified value. // DSNodeHandle DH = getDSNodeHandle (V); DSNode *node = DH.getNode(); //unsigned offset = DH.getOffset(); DEBUG(errs() << " check fields overlap at: " << offset << "\n"); // // If there is no DSNode, claim that it is not type safe. // if (DH.isNull()) { return false; } // // If the DSNode is completely folded, then we know for sure that it is not // type-safe. // if (node->isNodeCompletelyFolded()) return false; // // If the memory object represented by this DSNode can be manipulated by // external code or DSA has otherwise not finished analyzing all operations // on it, declare it type-unsafe. // if (node->isExternalNode() || node->isIncompleteNode()) return false; // // If the pointer to the memory object came from some source not understood // by DSA or somehow came from/escapes to the realm of integers, declare it // type-unsafe. // if (node->isUnknownNode() || node->isIntToPtrNode() || node->isPtrToIntNode()) { return false; } return !((NodeInfo[node])[offset]); }
// // Function: MergeConstantInitIntoNode() // // Description: // Merge the specified constant into the specified DSNode. // void GraphBuilder::MergeConstantInitIntoNode(DSNodeHandle &NH, Type* Ty, Constant *C) { // // Ensure a type-record exists... // DSNode *NHN = NH.getNode(); //NHN->mergeTypeInfo(Ty, NH.getOffset()); // // If we've found something of pointer type, create or find its DSNode and // make a link from the specified DSNode to the new DSNode describing the // pointer we've just found. // if (isa<PointerType>(Ty)) { NHN->mergeTypeInfo(Ty, NH.getOffset()); NH.addEdgeTo(getValueDest(C)); return; } // // If the type of the object (array element, structure field, etc.) is an // integer or floating point type, then just ignore it. It has no DSNode. // if (Ty->isIntOrIntVectorTy() || Ty->isFPOrFPVectorTy()) return; // // Handle aggregate constants. // if (ConstantArray *CA = dyn_cast<ConstantArray>(C)) { // // For an array, we don't worry about different elements pointing to // different objects; we essentially pretend that all array elements alias. // Type * ElementType = cast<ArrayType>(Ty)->getElementType(); for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { Constant * ConstElement = cast<Constant>(CA->getOperand(i)); MergeConstantInitIntoNode(NH, ElementType, ConstElement); } } else if (ConstantStruct *CS = dyn_cast<ConstantStruct>(C)) { // // For a structure, we need to merge each element of the constant structure // into the specified DSNode. However, we must also handle structures that // end with a zero-length array ([0 x sbyte]); this is a common C idiom // that continues to plague the world. // //NHN->mergeTypeInfo(Ty, NH.getOffset()); const StructLayout *SL = TD.getStructLayout(cast<StructType>(Ty)); for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) { DSNode *NHN = NH.getNode(); if (SL->getElementOffset(i) < SL->getSizeInBytes()) { // // Get the type and constant value of this particular element of the // constant structure. // Type * ElementType = cast<StructType>(Ty)->getElementType(i); Constant * ConstElement = cast<Constant>(CS->getOperand(i)); // // Get the offset (in bytes) into the memory object that we're // analyzing. // unsigned offset = NH.getOffset()+(unsigned)SL->getElementOffset(i); NHN->mergeTypeInfo(ElementType, offset); // // Create a new DSNodeHandle. This DSNodeHandle will point to the same // DSNode as the one we're constructing for our caller; however, it // will point into a different offset into that DSNode. // DSNodeHandle NewNH (NHN, offset); assert ((NHN->isNodeCompletelyFolded() || (NewNH.getOffset() == offset)) && "Need to resize DSNode!"); // // Recursively merge in this element of the constant struture into the // DSNode. // MergeConstantInitIntoNode(NewNH, ElementType, ConstElement); } else if (SL->getElementOffset(i) == SL->getSizeInBytes()) { // // If this is one of those cute structures that ends with a zero-length // array, just fold the DSNode now and get it over with. // DEBUG(errs() << "Zero size element at end of struct\n" ); NHN->foldNodeCompletely(); } else { assert(0 && "type was smaller than offsets of struct layout indicate"); } } } else if (isa<ConstantAggregateZero>(C) || isa<UndefValue>(C)) { // // Undefined values and NULL pointers have no DSNodes, so they do nothing. // } else { assert(0 && "Unknown constant type!"); } }
/// verify - This is the function which checks to make sure that all of the /// invariants established on the command line are true. /// void DSGC::verify(const DSGraph* G) { // Loop over all of the nodes, checking to see if any are collapsed... if (AbortIfAnyCollapsed) { for (DSGraph::node_const_iterator I = G->node_begin(), E = G->node_end(); I != E; ++I) if (I->isNodeCompletelyFolded()) { cerr << "Node is collapsed: "; I->print(cerr, G); abort(); } } if (!AbortIfCollapsed.empty() || !CheckFlags.empty() || !AbortIfMerged.empty()) { // Convert from a list to a set, because we don't have cl::set's yet. FIXME std::set<std::string> AbortIfCollapsedS(AbortIfCollapsed.begin(), AbortIfCollapsed.end()); std::set<std::string> AbortIfMergedS(AbortIfMerged.begin(), AbortIfMerged.end()); std::map<std::string, unsigned> CheckFlagsM; for (cl::list<std::string>::iterator I = CheckFlags.begin(), E = CheckFlags.end(); I != E; ++I) { std::string::size_type ColonPos = I->rfind(':'); if (ColonPos == std::string::npos) { cerr << "Error: '" << *I << "' is an invalid value for the --dsgc-check-flags option!\n"; abort(); } unsigned Flags = 0; for (unsigned C = ColonPos+1; C != I->size(); ++C) switch ((*I)[C]) { case 'S': Flags |= DSFlags::AllocaNode; break; case 'H': Flags |= DSFlags::HeapNode; break; case 'G': Flags |= DSFlags::GlobalNode; break; case 'U': Flags |= DSFlags::UnknownNode; break; case 'I': Flags |= DSFlags::IncompleteNode; break; case 'M': Flags |= DSFlags::ModifiedNode; break; case 'R': Flags |= DSFlags::ReadNode; break; case 'A': Flags |= DSFlags::ArrayNode; break; default: cerr << "Invalid DSNode flag!\n"; abort(); } CheckFlagsM[std::string(I->begin(), I->begin()+ColonPos)] = Flags; } // Now we loop over all of the scalars, checking to see if any are collapsed // that are not supposed to be, or if any are merged together. const DSGraph::ScalarMapTy &SM = G->getScalarMap(); std::map<DSNode*, std::string> AbortIfMergedNodes; for (DSGraph::ScalarMapTy::const_iterator I = SM.begin(), E = SM.end(); I != E; ++I) if (I->first->hasName() && I->second.getNode()) { const std::string &Name = I->first->getName(); DSNode *N = I->second.getNode(); // Verify it is not collapsed if it is not supposed to be... if (N->isNodeCompletelyFolded() && AbortIfCollapsedS.count(Name)) { cerr << "Node for value '%" << Name << "' is collapsed: "; N->print(cerr, G); abort(); } if (CheckFlagsM.count(Name) && CheckFlagsM[Name] != N->getNodeFlags()) { cerr << "Node flags are not as expected for node: " << Name << " (" << CheckFlagsM[Name] << ":" <<N->getNodeFlags() << ")\n"; N->print(cerr, G); abort(); } // Verify that it is not merged if it is not supposed to be... if (AbortIfMergedS.count(Name)) { if (AbortIfMergedNodes.count(N)) { cerr << "Nodes for values '%" << Name << "' and '%" << AbortIfMergedNodes[N] << "' is merged: "; N->print(cerr, G); abort(); } AbortIfMergedNodes[N] = Name; } } } }
// // Method: TransformCSSAllocasToMallocs() // // Description: // This method is given the set of DSNodes from the stack safety pass that // have been marked for promotion. It then finds all alloca instructions // that have not been marked type-unknown and promotes them to heap // allocations. // void ConvertUnsafeAllocas::TransformCSSAllocasToMallocs (Module & M, std::set<DSNode *> & cssAllocaNodes) { for (Module::iterator FI = M.begin(); FI != M.end(); ++FI) { // // Skip functions that have no DSGraph. These are probably functions with // no function body and are, hence, cannot be analyzed. // if (!(budsPass->hasDSGraph (*FI))) continue; // // Get the DSGraph for the current function. // DSGraph *DSG = budsPass->getDSGraph(*FI); // // Search for alloca instructions that need promotion and add them to the // worklist. // std::vector<AllocaInst *> Worklist; for (Function::iterator BB = FI->begin(); BB != FI->end(); ++BB) { for (BasicBlock::iterator ii = BB->begin(); ii != BB->end(); ++ii) { Instruction * I = ii; if (AllocaInst * AI = dyn_cast<AllocaInst>(I)) { // // Get the DSNode for the allocation. // DSNode *DSN = DSG->getNodeForValue(AI).getNode(); assert (DSN && "No DSNode for alloca!\n"); // // If the alloca is type-known, we do not need to promote it, so // don't bother with it. // if (DSN->isNodeCompletelyFolded()) continue; // // Determine if the DSNode for the alloca is one of those marked as // unsafe by the stack safety analysis pass. If not, then we do not // need to promote it. // if (cssAllocaNodes.find(DSN) == cssAllocaNodes.end()) continue; // // If the DSNode for this alloca is already listed in the // unsafeAllocaNode vector, remove it since we are processing it here // std::list<DSNode *>::iterator NodeI = find (unsafeAllocaNodes.begin(), unsafeAllocaNodes.end(), DSN); if (NodeI != unsafeAllocaNodes.end()) { unsafeAllocaNodes.erase(NodeI); } // // This alloca needs to be changed to a malloc. Add it to the // worklist. // Worklist.push_back (AI); } } } // // Update the statistics. // if (Worklist.size()) ConvAllocas += Worklist.size(); // // Convert everything in the worklist into a malloc instruction. // while (Worklist.size()) { // // Grab an alloca from the worklist. // AllocaInst * AI = Worklist.back(); Worklist.pop_back(); // // Get the DSNode for this alloca. // DSNode *DSN = DSG->getNodeForValue(AI).getNode(); assert (DSN && "No DSNode for alloca!\n"); // // Promote the alloca and remove it from the program. // promoteAlloca (AI, DSN); AI->getParent()->getInstList().erase(AI); } } }