void DFHack::Lua::Core::onUpdate(color_ostream &out) { using df::global::world; if (frame_timers.empty() && tick_timers.empty()) return; Lua::StackUnwinder frame(State); lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_TIMEOUTS_TOKEN); run_timers(out, State, frame_timers, frame[1], ++frame_idx); run_timers(out, State, tick_timers, frame[1], world->frame_counter); }
void setBarIndexes( std::multimap<ReducedFraction, MidiChord> &chords, const ReducedFraction &basicQuant, const ReducedFraction &lastTick, const TimeSigMap *sigmap) { if (chords.empty()) return; auto it = chords.begin(); for (int barIndex = 0;; ++barIndex) { // iterate over all measures by indexes const auto endBarTick = ReducedFraction::fromTicks(sigmap->bar2tick(barIndex + 1, 0)); if (endBarTick <= it->first) continue; for (; it != chords.end(); ++it) { const auto onTime = Quantize::findQuantizedChordOnTime(*it, basicQuant); #ifdef QT_DEBUG const auto barStart = ReducedFraction::fromTicks(sigmap->bar2tick(barIndex, 0)); Q_ASSERT_X(!(it->first >= barStart && onTime < barStart), "MChord::setBarIndexes", "quantized on time cannot be in previous bar"); #endif if (onTime < endBarTick) { it->second.barIndex = barIndex; continue; } break; } if (it == chords.end() || endBarTick > lastTick) break; } Q_ASSERT_X(areBarIndexesSet(chords), "MChord::setBarIndexes", "Not all bar indexes were set"); Q_ASSERT_X(areBarIndexesSuccessive(chords), "MChord::setBarIndexes", "Bar indexes are not successive"); }
void GroupTransformer::putData(RddPartition* output, std::multimap<PbMessagePtr, PbMessagePtr, idgs::store::less>& localCache) { if (!localCache.empty()) { PbMessagePtr key; std::vector<PbMessagePtr> values; for (auto it = localCache.begin(); it != localCache.end(); ++it) { if (idgs::store::equals_to()(const_cast<PbMessagePtr&>(it->first), key)) { values.push_back(it->second); } else { if (!values.empty()) { output->put(key, values); values.clear(); } values.clear(); key = it->first; values.push_back(it->second); } } if (!values.empty()) { output->put(key, values); values.clear(); } localCache.clear(); } }
std::vector<std::multimap<ReducedFraction, MidiChord>::const_iterator> findChordsForTimeRange( int voice, const ReducedFraction &onTime, const ReducedFraction &offTime, const std::multimap<ReducedFraction, MidiChord> &chords, const ReducedFraction &maxChordLength) { std::vector<std::multimap<ReducedFraction, MidiChord>::const_iterator> result; if (chords.empty()) return result; auto it = chords.lower_bound(offTime); if (it == chords.begin()) return result; --it; while (it->first + maxChordLength > onTime) { const MidiChord &chord = it->second; if (chord.voice == voice) { const auto chordInterval = std::make_pair(it->first, maxNoteOffTime(chord.notes)); const auto durationInterval = std::make_pair(onTime, offTime); if (MidiTuplet::haveIntersection(chordInterval, durationInterval)) result.push_back(it); } if (it == chords.begin()) break; --it; } return result; }
int tc_libcxx_containers_multimap_cons_compare(void) { { typedef test_compare<std::less<int> > C; const std::multimap<int, double, C> m(C(3)); TC_ASSERT_EXPR(m.empty()); TC_ASSERT_EXPR(m.begin() == m.end()); TC_ASSERT_EXPR(m.key_comp() == C(3)); } TC_SUCCESS_RESULT(); return 0; }
inline void operator<< (object::with_zone& o, const std::multimap<K,V>& v) { o.type = type::MAP; if(v.empty()) { o.via.map.ptr = NULL; o.via.map.size = 0; } else { object_kv* p = (object_kv*)o.zone->malloc(sizeof(object_kv)*v.size()); object_kv* const pend = p + v.size(); o.via.map.ptr = p; o.via.map.size = v.size(); typename std::multimap<K,V>::const_iterator it(v.begin()); do { p->key = object(it->first, o.zone); p->val = object(it->second, o.zone); ++p; ++it; } while(p < pend); } }
/** * @brief check if the order of execution of Actions in the List, based on their Precedence attribute, is correct and if in the List there are all the Actions */ bool ActionPluginFinalCallback::checkIfTheListIsCorrect( const std::multimap<int, Tuple>& multimapOfExecution, const std::list<std::set<Tuple> >& listOfExecution) { if (multimapOfExecution.empty()) if (listOfExecution.empty()) return true; else return false; // used to create a List (listOfExecutionFromMultimap) // with Tuples ordered by their Precedence attribute std::multimap<int, Tuple>::const_iterator itMOE = multimapOfExecution.begin(); int latestPrecedenceValue = itMOE->first; std::list < std::set<Tuple> > listOfExecutionFromMultimap; std::set < Tuple > currentSet; for (; itMOE != multimapOfExecution.end(); itMOE++) { if (itMOE->first != latestPrecedenceValue) { listOfExecutionFromMultimap.push_back(currentSet); currentSet.clear(); latestPrecedenceValue = itMOE->first; } currentSet.insert(itMOE->second); } listOfExecutionFromMultimap.push_back(currentSet); if (listOfExecution.size() != listOfExecutionFromMultimap.size()) return false; std::list<std::set<Tuple> >::const_iterator itLOE, itLOEFM; for (itLOE = listOfExecution.begin(), itLOEFM = listOfExecutionFromMultimap.begin(); itLOE != listOfExecution.end(), itLOEFM != listOfExecutionFromMultimap.end(); itLOE++, itLOEFM++) if (!checkIfThisSetsOfTupleContainsTheSameElements(*itLOEFM, *itLOE)) return false; return true; }
static void run_timers(color_ostream &out, lua_State *L, std::multimap<int,int> &timers, int table, int bound) { while (!timers.empty() && timers.begin()->first <= bound) { int id = timers.begin()->second; timers.erase(timers.begin()); lua_rawgeti(L, table, id); if (lua_isnil(L, -1)) lua_pop(L, 1); else { lua_pushnil(L); lua_rawseti(L, table, id); Lua::SafeCall(out, L, 0, 0); } } }
/** advance in play loop by rtick_inc ticks, possibly generate some * csoundScoreEvent calls. */ void step(MYFLT rtick_inc, MYFLT secs_per_tick , CSOUND * csound) { if (!playing) return; rtick += rtick_inc; int tick = (int)rtick % tickMax; if (tick == tick_prev) return; int events = 0; int loop0 = 0; int loop1 = 0; if (!ev.empty()) { if (steps && (tick < tick_prev)) // should be true only after the loop wraps (not after insert) { while (ev_pos != ev.end()) { if (_debug && (VERBOSE > 3)) ev_pos->second->ev_print(_debug); if (events < STEP_eventMax) ev_pos->second->event(csound, secs_per_tick); ++ev_pos; ++events; ++loop0; } ev_pos = ev.begin(); } while ((ev_pos != ev.end()) && (tick >= ev_pos->first)) { if (_debug && (VERBOSE > 3)) ev_pos->second->ev_print(_debug); if (events < STEP_eventMax) ev_pos->second->event(csound, secs_per_tick); ++ev_pos; ++events; ++loop1; } } tick_prev = tick; if (_debug && (VERBOSE>1) && (events >= STEP_eventMax)) fprintf(_debug, "WARNING: %i/%i events at once (%i, %i)\n", events, (int)ev.size(),loop0,loop1); ++steps; }
// Only call on io_service void ResetTimer() { const auto now = std::chrono::steady_clock::now(); UniqueLock unique_lock(mutex_); while (running_ && !data_.empty()) { auto map_front_it = data_.begin(); const auto timeout = map_front_it->first; if ( timeout <= now ) { // Effeciently extract the value so we can move it. auto event = std::move( map_front_it->second ); data_.erase(map_front_it); // Unlock incase callback calls a TimedActions method. unique_lock.unlock(); event_processor_(std::move(event), std::error_code()); unique_lock.lock(); } else { timeout_timer_.expires_at(timeout); timeout_timer_.async_wait( boost::bind( &TimedEvents<Event>::HandleTimeout, this->shared_from_this(), boost::asio::placeholders::error ) ); break; } } }
/** * Return public keys or hashes from scriptPubKey, for 'standard' transaction types. */ bool Solver(const CScript& scriptPubKeyIn, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet) { // Templates static std::multimap<txnouttype, CScript> mTemplates; if (mTemplates.empty()) { // Standard tx, sender provides pubkey, receiver adds signature mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); // Syscoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey mTemplates.insert(std::make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); // Sender provides N pubkeys, receivers provides M signatures mTemplates.insert(std::make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); } // SYSCOIN check to see if this is a syscoin service transaction, if so get the scriptPubKey by extracting service specific script information CScript scriptPubKey; CScript scriptPubKeyOut; if (RemoveSyscoinScript(scriptPubKeyIn, scriptPubKeyOut)) scriptPubKey = scriptPubKeyOut; else scriptPubKey = scriptPubKeyIn; vSolutionsRet.clear(); // Shortcut for pay-to-script-hash, which are more constrained than the other types: // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL if (scriptPubKey.IsPayToScriptHash()) { typeRet = TX_SCRIPTHASH; std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); vSolutionsRet.push_back(hashBytes); return true; } // Provably prunable, data-carrying output // // So long as script passes the IsUnspendable() test and all but the first // byte passes the IsPushOnly() test we don't care what exactly is in the // script. if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) { typeRet = TX_NULL_DATA; return true; } // Scan templates const CScript& script1 = scriptPubKey; BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates) { const CScript& script2 = tplate.second; vSolutionsRet.clear(); opcodetype opcode1, opcode2; std::vector<unsigned char> vch1, vch2; // Compare CScript::const_iterator pc1 = script1.begin(); CScript::const_iterator pc2 = script2.begin(); while (true) { if (pc1 == script1.end() && pc2 == script2.end()) { // Found a match typeRet = tplate.first; if (typeRet == TX_MULTISIG) { // Additional checks for TX_MULTISIG: unsigned char m = vSolutionsRet.front()[0]; unsigned char n = vSolutionsRet.back()[0]; if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n) return false; } return true; } if (!script1.GetOp(pc1, opcode1, vch1)) break; if (!script2.GetOp(pc2, opcode2, vch2)) break; // Template matching opcodes: if (opcode2 == OP_PUBKEYS) { while (vch1.size() >= 33 && vch1.size() <= 65) { vSolutionsRet.push_back(vch1); if (!script1.GetOp(pc1, opcode1, vch1)) break; } if (!script2.GetOp(pc2, opcode2, vch2)) break; // Normal situation is to fall through // to other if/else statements } if (opcode2 == OP_PUBKEY) { if (vch1.size() < 33 || vch1.size() > 65) break; vSolutionsRet.push_back(vch1); } else if (opcode2 == OP_PUBKEYHASH) { if (vch1.size() != sizeof(uint160)) break; vSolutionsRet.push_back(vch1); } else if (opcode2 == OP_SMALLINTEGER) { // Single-byte small integer pushed onto vSolutions if (opcode1 == OP_0 || (opcode1 >= OP_1 && opcode1 <= OP_16)) { char n = (char)CScript::DecodeOP_N(opcode1); vSolutionsRet.push_back(valtype(1, n)); } else break; } else if (opcode1 != opcode2 || vch1 != vch2) { // Others must match exactly break; } } } vSolutionsRet.clear(); typeRet = TX_NONSTANDARD; return false; }
///===================================================== /// ///===================================================== inline bool Path::HasFinishedPath() const{ return (m_path.empty() || (m_openList.empty() && !m_closedList.empty())); }
///update called every complete cycle of service loop bool CMonitorService::update () { Server->update(); uint iclient; for (iclient=0; iclient<Clients.size(); ++iclient) { CMonitorClient &client = *Clients[iclient]; if (client.Authentificated) { client.update(); } } // Sent bad login msg to clients at the right time NLMISC::TTime currentTime = NLMISC::CTime::getLocalTime(); while (!BadLoginClients.empty() && BadLoginClients.begin()->first <= currentTime) { CMonitorClient *client = BadLoginClients.begin()->second; if (client != NULL) { CMessage msgout; msgout.setType("AUTHENT_INVALID"); Server->send(msgout, client->getSock()); client->BadLogin = false; // allow to accept login again for that client } BadLoginClients.erase(BadLoginClients.begin()); } /* if (!Clients.empty() && !Entites.empty()) { // Update some primitive static uint primitiveToUpdate = 0; CConfigFile::CVar *var = ConfigFile.getVarPtr ("UpdatePerTick"); uint count = 10; if (var && (var->Type == CConfigFile::CVar::T_INT)) count = var->asInt(); // Loop to the beginning if (primitiveToUpdate >= Entites.size()) primitiveToUpdate = 0; // Resize the client array // For each client uint i; for (i=0; i<Clients.size(); i++) { nlassert (Clients[i]->Entites.size() <= Entites.size()); Clients[i]->Entites.resize (Entites.size()); } // For each primitive uint firstPrimitiveToUpdate = primitiveToUpdate; while (count) { // Present ? if (Entites[primitiveToUpdate].Flags & CEntityEntry::Present) { // One more count--; // Get the primitive position TDataSetRow entityIndex = TDataSetRow::createFromRawIndex (primitiveToUpdate); CMirrorPropValueRO<TYPE_POSX> valueX( TheDataset, entityIndex, DSPropertyPOSX ); CMirrorPropValueRO<TYPE_POSY> valueY( TheDataset, entityIndex, DSPropertyPOSY ); CMonitorClient::CPosData posData; posData.X = (float)valueX / 1000.f; posData.Y = (float)valueY / 1000.f; // For each client for (i=0; i<Clients.size(); i++) { // The client CMonitorClient &client = *Clients[i]; // Send position ? bool sendPos = false; // Clipped ? const NLMISC::CVector &topLeft = client.getTopLeft(); const NLMISC::CVector &bottomRight = client.getBottomRight(); if ((posData.X>=topLeft.x) && (posData.Y>=topLeft.y) && (posData.X<=bottomRight.x) && (posData.Y<=bottomRight.y)) { // Inside if (client.Entites[primitiveToUpdate].Flags & CMonitorClient::CEntityEntry::Present) { // Send a POS message sendPos = true; } else { // Send a ADD and a POS message CMirrorPropValueRO<TYPE_NAME_STRING_ID> stringId( TheDataset, entityIndex, DSPropertyNAME_STRING_ID); CMonitorClient::CAddData addData; addData.Id = primitiveToUpdate; addData.StringId = stringId; addData.EntityId = TheDataset.getEntityId (entityIndex); client.Add.push_back (addData); sendPos = true; } } else { // Outside // Inside if (client.Entites[primitiveToUpdate].Flags & CMonitorClient::CEntityEntry::Present) { // Send a RMV message client.Rmv.push_back (primitiveToUpdate); } } // Send position ? if (sendPos) { CMirrorPropValueRO<TYPE_ORIENTATION> valueT( TheDataset, entityIndex, DSPropertyORIENTATION ); posData.Id = primitiveToUpdate; posData.Tetha = valueT; client.Pos.push_back (posData); } } } else { // Not present for (i=0; i<Clients.size(); i++) { // The client if (Clients[i]->Entites[primitiveToUpdate].Flags & CMonitorClient::CEntityEntry::Present) { // One more count--; // Send a RMV message Clients[i]->Rmv.push_back (primitiveToUpdate); } } } // Next primitive primitiveToUpdate++; // Loop to the beginning if (primitiveToUpdate >= Entites.size()) primitiveToUpdate = 0; // Return to the first ? if (firstPrimitiveToUpdate == primitiveToUpdate) break; } // For each client for (i=0; i<Clients.size(); i++) Clients[i].update (); } */ return true; }
bool Polish::Write(const std::string& filename, const std::multimap<int, Airspace>& airspaces) { if (airspaces.empty()) { AirspaceConverter::LogMessage("Polish output: no airspace, nothing to write", false); return false; } // Check if has the right extension if (!boost::iequals(boost::filesystem::path(filename).extension().string(), ".mp")) { AirspaceConverter::LogMessage("ERROR: Expected MP extension but found: " + boost::filesystem::path(filename).extension().string(), true); return false; } if (file.is_open()) file.close(); file.open(filename, std::ios::out | std::ios::trunc | std::ios::binary); if (!file.is_open() || file.bad()) { AirspaceConverter::LogMessage("ERROR: Unable to open output file: " + filename, true); return false; } AirspaceConverter::LogMessage("Writing output file: " + filename, false); WriteHeader(filename); // Go trough all airspaces for (const std::pair<const int,Airspace>& pair : airspaces) { // Get the airspace const Airspace& a = pair.second; // Just a couple if assertions assert(a.GetNumberOfPoints() > 3); assert(a.GetFirstPoint()==a.GetLastPoint()); // Determine if it's a POLYGON or a POLYLINE if (a.GetType() == Airspace::PROHIBITED || a.GetType() == Airspace::CTR || a.GetType() == Airspace::DANGER) { file << "[POLYGON]\n" //<< "Type="<< types[a.GetType()] <<"\n"; //TODO... << "Type=0x18" <<"\n"; } else { file << "[POLYLINE]\n" << "Type=0x07\n"; //TODO.... } // Add the label file << "Label="<<MakeLabel(a)<<"\n"; file << "Levels=3\n"; // Insert all the points file << "Data0="; double lat,lon; for (unsigned int i=0; i<a.GetNumberOfPoints()-1; i++) { a.GetPointAt(i).GetLatLon(lat,lon); file << "(" << lat << "," << lon << "),"; } a.GetLastPoint().GetLatLon(lat,lon); file << "(" << lat << "," << lon << ")\n"; //file<< "EndLevel=4\n"; // Close the element file << "[END]\n\n"; } file.close(); return true; }
/// visitGraph - Visit the functions in the specified graph, updating the /// specified lattice values for all of their uses. /// void StructureFieldVisitorBase:: visitGraph(DSGraph &DSG, std::multimap<DSNode*, LatticeValue*> &NodeLVs) { assert(!NodeLVs.empty() && "No lattice values to compute!"); // To visit a graph, first step, we visit the instruction making up each // function in the graph, but ignore calls when processing them. We handle // call nodes explicitly by looking at call nodes in the graph if needed. We // handle instructions before calls to avoid interprocedural analysis if we // can drive lattice values to bottom early. // SFVInstVisitor IV(DSG, Callbacks, NodeLVs); for (DSGraph::retnodes_iterator FI = DSG.retnodes_begin(), E = DSG.retnodes_end(); FI != E; ++FI) for (Function::iterator BB = FI->first->begin(), E = FI->first->end(); BB != E; ++BB) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) if (IV.visit(*I) && NodeLVs.empty()) return; // Nothing left to analyze. // Keep track of which actual direct callees are handled. std::set<Function*> CalleesHandled; // Once we have visited all of the instructions in the function bodies, if // there are lattice values that have not been driven to bottom, see if any of // the nodes involved are passed into function calls. If so, we potentially // have to recursively traverse the call graph. for (DSGraph::fc_iterator CS = DSG.fc_begin(), E = DSG.fc_end(); CS != E; ++CS) { // Figure out the mapping from a node in the caller (potentially several) // nodes in the callee. DSGraph::NodeMapTy CallNodeMap; Instruction *TheCall = CS->getCallSite().getInstruction(); // If this is an indirect function call, assume nothing gets passed through // it. FIXME: THIS IS BROKEN! Just get the ECG for the fn ptr if it's not // direct. if (CS->isIndirectCall()) continue; // If this is an external function call, it cannot be involved with this // node, because otherwise the node would be marked incomplete! if (CS->getCalleeFunc()->isExternal()) continue; // If we can handle this function call, remove it from the set of direct // calls found by the visitor. CalleesHandled.insert(CS->getCalleeFunc()); std::vector<DSNodeHandle> Args; DSGraph *CG = &ECG.getDSGraph(*CS->getCalleeFunc()); CG->getFunctionArgumentsForCall(CS->getCalleeFunc(), Args); if (!CS->getRetVal().isNull()) DSGraph::computeNodeMapping(Args[0], CS->getRetVal(), CallNodeMap); for (unsigned i = 0, e = CS->getNumPtrArgs(); i != e; ++i) { if (i == Args.size()-1) break; DSGraph::computeNodeMapping(Args[i+1], CS->getPtrArg(i), CallNodeMap); } Args.clear(); // The mapping we just computed maps from nodes in the callee to nodes in // the caller, so we can't query it efficiently. Instead of going through // the trouble of inverting the map to do this (linear time with the size of // the mapping), we just do a linear search to see if any affected nodes are // passed into this call. bool CallCanModifyDataFlow = false; for (DSGraph::NodeMapTy::iterator MI = CallNodeMap.begin(), E = CallNodeMap.end(); MI != E; ++MI) if (NodeLVs.count(MI->second.getNode())) // Okay, the node is passed in, check to see if the call might do // something interesting to it (i.e. if analyzing the call can produce // anything other than "top"). if ((CallCanModifyDataFlow = NodeCanPossiblyBeInteresting(MI->first, Callbacks))) break; // If this function call cannot impact the analysis (either because the // nodes we are tracking are not passed into the call, or the DSGraph for // the callee tells us that analysis of the callee can't provide interesting // information), ignore it. if (!CallCanModifyDataFlow) continue; // Okay, either compute analysis results for the callee function, or reuse // results previously computed. std::multimap<DSNode*, LatticeValue*> &CalleeFacts = getCalleeFacts(*CG); // Merge all of the facts for the callee into the facts for the caller. If // this reduces anything in the caller to 'bottom', remove them. for (DSGraph::NodeMapTy::iterator MI = CallNodeMap.begin(), E = CallNodeMap.end(); MI != E; ++MI) { // If we have Lattice facts in the caller for this node in the callee, // merge any information from the callee into the caller. // If the node is not accessed in the callee at all, don't update. if (MI->first->getType() == Type::VoidTy) continue; // If there are no data-flow facts live in the caller for this node, don't // both processing it. std::multimap<DSNode*, LatticeValue*>::iterator NLVI = NodeLVs.find(MI->second.getNode()); if (NLVI == NodeLVs.end()) continue; // Iterate over all of the lattice values that have corresponding fields // in the callee, merging in information as we go. Be careful about the // fact that the callee may get passed the address of a substructure and // other funny games. //if (CalleeFacts.count(const_cast<DSNode*>(MI->first)) == 0) { DSNode *CalleeNode = const_cast<DSNode*>(MI->first); unsigned CalleeNodeOffset = MI->second.getOffset(); while (NLVI->first == MI->second.getNode()) { // Figure out what offset in the callee this field would land. unsigned FieldOff = NLVI->second->getFieldOffset()+CalleeNodeOffset; // If the field is not within the callee node, ignore it. if (FieldOff >= CalleeNode->getSize()) { ++NLVI; continue; } // Okay, check to see if we have a lattice value for the field at offset // FieldOff in the callee node. const LatticeValue *CalleeLV = 0; std::multimap<DSNode*, LatticeValue*>::iterator CFI = CalleeFacts.lower_bound(CalleeNode); for (; CFI != CalleeFacts.end() && CFI->first == CalleeNode; ++CFI) if (CFI->second->getFieldOffset() == FieldOff) { CalleeLV = CFI->second; // Found it! break; } // If we don't, the lattice value hit bottom and we should remove the // lattice value in the caller. if (!CalleeLV) { delete NLVI->second; // The lattice value hit bottom. NodeLVs.erase(NLVI++); continue; } // Finally, if we did find a corresponding entry, merge the information // into the caller's lattice value and keep going. if (NLVI->second->mergeInValue(CalleeLV)) { // Okay, merging these two caused the caller value to hit bottom. // Remove it. delete NLVI->second; // The lattice value hit bottom. NodeLVs.erase(NLVI++); } ++NLVI; // We successfully merged in some information! } // If we ran out of facts to prove, just exit. if (NodeLVs.empty()) return; } } // The local analysis pass inconveniently discards many local function calls // from the graph if they are to known functions. Loop over direct function // calls not handled above and visit them as appropriate. while (!IV.DirectCallSites.empty()) { Instruction *Call = *IV.DirectCallSites.begin(); IV.DirectCallSites.erase(IV.DirectCallSites.begin()); // Is this one actually handled by DSA? if (CalleesHandled.count(cast<Function>(Call->getOperand(0)))) continue; // Collect the pointers involved in this call. std::vector<Value*> Pointers; if (isa<PointerType>(Call->getType())) Pointers.push_back(Call); for (unsigned i = 1, e = Call->getNumOperands(); i != e; ++i) if (isa<PointerType>(Call->getOperand(i)->getType())) Pointers.push_back(Call->getOperand(i)); // If this is an intrinsic function call, figure out which one. unsigned IID = cast<Function>(Call->getOperand(0))->getIntrinsicID(); for (unsigned i = 0, e = Pointers.size(); i != e; ++i) { // If any of our lattice values are passed into this call, which is // specially handled by the local analyzer, inform the lattice function. DSNode *N = DSG.getNodeForValue(Pointers[i]).getNode(); for (std::multimap<DSNode*, LatticeValue*>::iterator LVI = NodeLVs.lower_bound(N); LVI != NodeLVs.end() && LVI->first == N;) { bool AtBottom = false; switch (IID) { default: AtBottom = LVI->second->visitRecognizedCall(*Call); break; case Intrinsic::memset: if (Callbacks & Visit::Stores) AtBottom = LVI->second->visitMemSet(*cast<CallInst>(Call)); break; } if (AtBottom) { delete LVI->second; NodeLVs.erase(LVI++); } else { ++LVI; } } } } }
/// ProcessNodesReachableFromGlobals - If we inferred anything about nodes /// reachable from globals, we have to make sure that we incorporate data for /// all graphs that include those globals due to the nature of the globals /// graph. /// void StructureFieldVisitorBase:: ProcessNodesReachableFromGlobals(DSGraph &DSG, std::multimap<DSNode*,LatticeValue*> &NodeLVs){ // Start by marking all nodes reachable from globals. DSScalarMap &SM = DSG.getScalarMap(); if (SM.global_begin() == SM.global_end()) return; hash_set<const DSNode*> Reachable; for (DSScalarMap::global_iterator GI = SM.global_begin(), E = SM.global_end(); GI != E; ++GI) SM[*GI].getNode()->markReachableNodes(Reachable); if (Reachable.empty()) return; // If any of the nodes with dataflow facts are reachable from the globals // graph, we have to do the GG processing step. bool MustProcessThroughGlobalsGraph = false; for (std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.begin(), E = NodeLVs.end(); I != E; ++I) if (Reachable.count(I->first)) { MustProcessThroughGlobalsGraph = true; break; } if (!MustProcessThroughGlobalsGraph) return; Reachable.clear(); // Compute the mapping from DSG to the globals graph. DSGraph::NodeMapTy DSGToGGMap; DSG.computeGToGGMapping(DSGToGGMap); // Most of the times when we find facts about things reachable from globals we // we are in the main graph. This means that we have *all* of the globals // graph in this DSG. To be efficient, we compute the minimum set of globals // that can reach any of the NodeLVs facts. // // I'm not aware of any wonderful way of computing the set of globals that // points to the set of nodes in NodeLVs that is not N^2 in either NodeLVs or // the number of globals, except to compute the inverse of DSG. As such, we // compute the inverse graph of DSG, which basically has the edges going from // pointed to nodes to pointing nodes. Because we only care about one // connectedness properties, we ignore field info. In addition, we only // compute inverse of the portion of the graph reachable from the globals. std::set<std::pair<DSNode*,DSNode*> > InverseGraph; for (DSScalarMap::global_iterator GI = SM.global_begin(), E = SM.global_end(); GI != E; ++GI) ComputeInverseGraphFrom(SM[*GI].getNode(), InverseGraph); // Okay, now that we have our bastardized inverse graph, compute the set of // globals nodes reachable from our lattice nodes. for (std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.begin(), E = NodeLVs.end(); I != E; ++I) ComputeNodesReachableFrom(I->first, InverseGraph, Reachable); // Now that we know which nodes point to the data flow facts, figure out which // globals point to the data flow facts. std::set<GlobalValue*> Globals; for (hash_set<const DSNode*>::iterator I = Reachable.begin(), E = Reachable.end(); I != E; ++I) Globals.insert((*I)->globals_begin(), (*I)->globals_end()); // Finally, loop over all of the DSGraphs for the program, computing // information for the graph if not done already, mapping the result into our // context. for (hash_map<const Function*, DSGraph*>::iterator GI = ECG.DSInfo.begin(), E = ECG.DSInfo.end(); GI != E; ++GI) { DSGraph &FG = *GI->second; // Graphs can contain multiple functions, only process the graph once. if (GI->first != FG.retnodes_begin()->first || // Also, do not bother reprocessing DSG. &FG == &DSG) continue; bool GraphUsesGlobal = false; for (std::set<GlobalValue*>::iterator I = Globals.begin(), E = Globals.end(); I != E; ++I) if (FG.getScalarMap().count(*I)) { GraphUsesGlobal = true; break; } // If this graph does not contain the global at all, there is no reason to // even think about it. if (!GraphUsesGlobal) continue; // Otherwise, compute the full set of dataflow effects of the function. std::multimap<DSNode*, LatticeValue*> &FGF = getCalleeFacts(FG); //std::cerr << "Computed: " << FG.getFunctionNames() << "\n"; #if 0 for (std::multimap<DSNode*, LatticeValue*>::iterator I = FGF.begin(), E = FGF.end(); I != E; ++I) I->second->dump(); #endif // Compute the mapping of nodes in the globals graph to the function's // graph. Note that this function graph may not have nodes (or may have // fragments of full nodes) in the globals graph, and we don't want this to // pessimize the analysis. std::multimap<const DSNode*, std::pair<DSNode*,int> > GraphMap; DSGraph::NodeMapTy GraphToGGMap; FG.computeGToGGMapping(GraphToGGMap); // "Invert" the mapping. We compute the mapping from the start of a global // graph node to a place in the graph's node. Note that not all of the GG // node may be present in the graphs node, so there may be a negative offset // involved. while (!GraphToGGMap.empty()) { DSNode *GN = const_cast<DSNode*>(GraphToGGMap.begin()->first); DSNodeHandle &GGNH = GraphToGGMap.begin()->second; GraphMap.insert(std::make_pair(GGNH.getNode(), std::make_pair(GN, -GGNH.getOffset()))); GraphToGGMap.erase(GraphToGGMap.begin()); } // Loop over all of the dataflow facts that we have computed, mapping them // to the globals graph. for (std::multimap<DSNode*, LatticeValue*>::iterator I = NodeLVs.begin(), E = NodeLVs.end(); I != E; ) { bool FactHitBottom = false; //I->second->dump(); assert(I->first->getParentGraph() == &DSG); assert(I->second->getNode()->getParentGraph() == &DSG); // Node is in the GG? DSGraph::NodeMapTy::iterator DSGToGGMapI = DSGToGGMap.find(I->first); if (DSGToGGMapI != DSGToGGMap.end()) { DSNodeHandle &GGNH = DSGToGGMapI->second; const DSNode *GGNode = GGNH.getNode(); unsigned DSGToGGOffset = GGNH.getOffset(); // See if there is a node in FG that corresponds to this one. If not, // no information will be computed in this scope, as the memory is not // accessed. std::multimap<const DSNode*, std::pair<DSNode*,int> >::iterator GMI = GraphMap.find(GGNode); // LatticeValOffset - The offset from the start of the GG Node to the // start of the field we are interested in. unsigned LatticeValOffset = I->second->getFieldOffset()+DSGToGGOffset; // Loop over all of the nodes in FG that correspond to this single node // in the GG. for (; GMI != GraphMap.end() && GMI->first == GGNode; ++GMI) { // Compute the offset to the field in the user graph. unsigned FieldOffset = LatticeValOffset - GMI->second.second; // If the field is within the amount of memory accessed by this scope, // then there must be a corresponding lattice value. DSNode *FGNode = GMI->second.first; if (FieldOffset < FGNode->getSize()) { LatticeValue *CorrespondingLV = 0; std::multimap<DSNode*, LatticeValue*>::iterator FGFI = FGF.find(FGNode); for (; FGFI != FGF.end() && FGFI->first == FGNode; ++FGFI) if (FGFI->second->getFieldOffset() == FieldOffset) { CorrespondingLV = FGFI->second; break; } // Finally, if either there was no corresponding fact (because it // hit bottom in this scope), or if merging the two pieces of // information makes it hit bottom, remember this. if (CorrespondingLV == 0 || I->second->mergeInValue(CorrespondingLV)) FactHitBottom = true; } } } if (FactHitBottom) { delete I->second; NodeLVs.erase(I++); if (NodeLVs.empty()) return; } else { ++I; } } } }
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet) { // Templates static std::multimap<txnouttype, CScript> mTemplates; if (mTemplates.empty()) { // Standard tx, sender provides pubkey, receiver adds signature mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey mTemplates.insert(std::make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); // Sender provides N pubkeys, receivers provides M signatures mTemplates.insert(std::make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); } vSolutionsRet.clear(); // If we have a name script, strip the prefix const CNameScript nameOp(scriptPubKey); const CScript& script1 = nameOp.getAddress(); // Shortcut for pay-to-script-hash, which are more constrained than the other types: // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL if (script1.IsPayToScriptHash(false)) { typeRet = TX_SCRIPTHASH; std::vector<unsigned char> hashBytes(script1.begin()+2, script1.begin()+22); vSolutionsRet.push_back(hashBytes); return true; } int witnessversion; std::vector<unsigned char> witnessprogram; if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { if (witnessversion == 0 && witnessprogram.size() == 20) { typeRet = TX_WITNESS_V0_KEYHASH; vSolutionsRet.push_back(witnessprogram); return true; } if (witnessversion == 0 && witnessprogram.size() == 32) { typeRet = TX_WITNESS_V0_SCRIPTHASH; vSolutionsRet.push_back(witnessprogram); return true; } if (witnessversion != 0) { typeRet = TX_WITNESS_UNKNOWN; vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion}); vSolutionsRet.push_back(std::move(witnessprogram)); return true; } return false; } // Provably prunable, data-carrying output // // So long as script passes the IsUnspendable() test and all but the first // byte passes the IsPushOnly() test we don't care what exactly is in the // script. if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) { typeRet = TX_NULL_DATA; return true; } // Scan templates for (const std::pair<txnouttype, CScript>& tplate : mTemplates) { const CScript& script2 = tplate.second; vSolutionsRet.clear(); opcodetype opcode1, opcode2; std::vector<unsigned char> vch1, vch2; // Compare CScript::const_iterator pc1 = script1.begin(); CScript::const_iterator pc2 = script2.begin(); while (true) { if (pc1 == script1.end() && pc2 == script2.end()) { // Found a match typeRet = tplate.first; if (typeRet == TX_MULTISIG) { // Additional checks for TX_MULTISIG: unsigned char m = vSolutionsRet.front()[0]; unsigned char n = vSolutionsRet.back()[0]; if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n) return false; } return true; } if (!script1.GetOp(pc1, opcode1, vch1)) break; if (!script2.GetOp(pc2, opcode2, vch2)) break; // Template matching opcodes: if (opcode2 == OP_PUBKEYS) { while (vch1.size() >= 33 && vch1.size() <= 65) { vSolutionsRet.push_back(vch1); if (!script1.GetOp(pc1, opcode1, vch1)) break; } if (!script2.GetOp(pc2, opcode2, vch2)) break; // Normal situation is to fall through // to other if/else statements } if (opcode2 == OP_PUBKEY) { if (vch1.size() < 33 || vch1.size() > 65) break; vSolutionsRet.push_back(vch1); } else if (opcode2 == OP_PUBKEYHASH) { if (vch1.size() != sizeof(uint160)) break; vSolutionsRet.push_back(vch1); } else if (opcode2 == OP_SMALLINTEGER) { // Single-byte small integer pushed onto vSolutions if (opcode1 == OP_0 || (opcode1 >= OP_1 && opcode1 <= OP_16)) { char n = (char)CScript::DecodeOP_N(opcode1); vSolutionsRet.push_back(valtype(1, n)); } else break; } else if (opcode1 != opcode2 || vch1 != vch2) { // Others must match exactly break; } } } vSolutionsRet.clear(); typeRet = TX_NONSTANDARD; return false; }
bool empty() const { return m_functions.empty(); }