| 63 | } |
| 64 | |
| 65 | GasMeter::GasConsumption PathGasMeter::handleQueueItem() |
| 66 | { |
| 67 | assertThrow(!m_queue.empty(), OptimizerException, ""); |
| 68 | |
| 69 | std::unique_ptr<GasPath> path = std::move(m_queue.rbegin()->second); |
| 70 | m_queue.erase(--m_queue.end()); |
| 71 | |
| 72 | std::shared_ptr<KnownState> state = path->state; |
| 73 | GasMeter meter(state, m_evmVersion, path->largestMemoryAccess); |
| 74 | ExpressionClasses& classes = state->expressionClasses(); |
| 75 | GasMeter::GasConsumption gas = path->gas; |
| 76 | size_t index = path->index; |
| 77 | |
| 78 | if (index >= m_items.size() || (index > 0 && m_items.at(index).type() != Tag)) |
| 79 | // Invalid jump usually provokes an out-of-gas exception, but we want to give an upper |
| 80 | // bound on the gas that is needed without changing the behaviour, so it is fine to |
| 81 | // return the current gas value. |
| 82 | return gas; |
| 83 | |
| 84 | std::set<u256> jumpTags; |
| 85 | for (; index < m_items.size() && !gas.isInfinite; ++index) |
| 86 | { |
| 87 | bool branchStops = false; |
| 88 | jumpTags.clear(); |
| 89 | AssemblyItem const& item = m_items.at(index); |
| 90 | if (item.type() == Tag || item == AssemblyItem(Instruction::JUMPDEST)) |
| 91 | { |
| 92 | // Do not allow any backwards jump. This is quite restrictive but should work for |
| 93 | // the simplest things. |
| 94 | if (path->visitedJumpdests.count(index)) |
| 95 | return GasMeter::GasConsumption::infinite(); |
| 96 | path->visitedJumpdests.insert(index); |
| 97 | } |
| 98 | else if (item == AssemblyItem(Instruction::JUMP)) |
| 99 | { |
| 100 | branchStops = true; |
| 101 | jumpTags = state->tagsInExpression(state->relativeStackElement(0)); |
| 102 | if (jumpTags.empty()) // unknown jump destination |
| 103 | return GasMeter::GasConsumption::infinite(); |
| 104 | } |
| 105 | else if (item == AssemblyItem(Instruction::JUMPI)) |
| 106 | { |
| 107 | ExpressionClasses::Id condition = state->relativeStackElement(-1); |
| 108 | if (classes.knownNonZero(condition) || !classes.knownZero(condition)) |
| 109 | { |
| 110 | jumpTags = state->tagsInExpression(state->relativeStackElement(0)); |
| 111 | if (jumpTags.empty()) // unknown jump destination |
| 112 | return GasMeter::GasConsumption::infinite(); |
| 113 | } |
| 114 | branchStops = classes.knownNonZero(condition); |
| 115 | } |
| 116 | else if (SemanticInformation::altersControlFlow(item)) |
| 117 | branchStops = true; |
| 118 | |
| 119 | gas += meter.estimateMax(item); |
| 120 | |
| 121 | for (u256 const& tag: jumpTags) |
| 122 | { |
nothing calls this directly
no test coverage detected