diff --git a/Assembly.cpp b/Assembly.cpp index 8c6591885..a9ee96199 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -127,7 +127,10 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con _out << " PUSH \"" << m_strings.at((h256)i.data()) << "\""; break; case PushTag: - _out << " PUSH [tag" << dec << i.data() << "]"; + if (i.data() == 0) + _out << " PUSH [ErrorTag]"; + else + _out << " PUSH [tag" << dec << i.data() << "]"; break; case PushSub: _out << " PUSH [$" << h256(i.data()).abridged() << "]"; @@ -207,8 +210,12 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes createJsonValue("PUSH tag", i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); break; case PushTag: - collection.append( - createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, string(i.data()))); + if (i.data() == 0) + collection.append( + createJsonValue("PUSH [ErrorTag]", i.getLocation().start, i.getLocation().end, "")); + else + collection.append( + createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, string(i.data()))); break; case PushSub: collection.append( @@ -226,7 +233,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes collection.append( createJsonValue("tag", i.getLocation().start, i.getLocation().end, string(i.data()))); collection.append( - createJsonValue("JUMDEST", i.getLocation().start, i.getLocation().end)); + createJsonValue("JUMPDEST", i.getLocation().start, i.getLocation().end)); break; case PushData: collection.append(createJsonValue("PUSH data", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); @@ -387,6 +394,11 @@ bytes Assembly::assemble() const // m_data must not change from here on for (AssemblyItem const& i: m_items) + { + // store position of the invalid jump destination + if (i.type() != Tag && tagPos[0] == 0) + tagPos[0] = ret.size(); + switch (i.type()) { case Operation: @@ -448,17 +460,23 @@ bytes Assembly::assemble() const } case Tag: tagPos[(unsigned)i.data()] = ret.size(); + assertThrow(i.data() != 0, AssemblyException, ""); ret.push_back((byte)Instruction::JUMPDEST); break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); } - + } for (auto const& i: tagRef) { bytesRef r(ret.data() + i.first, bytesPerTag); - //@todo in the failure case, we could use the position of the invalid jumpdest - toBigEndian(i.second < tagPos.size() ? tagPos[i.second] : (1 << (8 * bytesPerTag)) - 1, r); + auto tag = i.second; + if (tag >= tagPos.size()) + tag = 0; + if (tag == 0) + assertThrow(tagPos[tag] != 0, AssemblyException, ""); + + toBigEndian(tagPos[tag], r); } if (!m_data.empty()) diff --git a/Assembly.h b/Assembly.h index b4850f7d0..3c82125a1 100644 --- a/Assembly.h +++ b/Assembly.h @@ -67,6 +67,8 @@ public: AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMPI); return ret; } + AssemblyItem errorTag() { return AssemblyItem(PushTag, 0); } + template Assembly& operator<<(T const& _d) { append(_d); return *this; } AssemblyItems const& getItems() const { return m_items; } AssemblyItem const& back() const { return m_items.back(); } @@ -97,7 +99,6 @@ public: const StringMap &_sourceCodes = StringMap(), bool _inJsonFormat = false ) const; - protected: std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const; void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } @@ -109,7 +110,8 @@ private: Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string()) const; protected: - unsigned m_usedTags = 0; + // 0 is reserved for exception + unsigned m_usedTags = 1; AssemblyItems m_items; mutable std::map m_data; std::vector m_subs; diff --git a/AssemblyItem.h b/AssemblyItem.h index 7d8f3d9a4..9eca0a7d1 100644 --- a/AssemblyItem.h +++ b/AssemblyItem.h @@ -65,7 +65,7 @@ public: /// @returns the instruction of this item (only valid if type() == Operation) Instruction instruction() const { return Instruction(byte(m_data)); } - /// @returns true iff the type and data of the items are equal. + /// @returns true if the type and data of the items are equal. bool operator==(AssemblyItem const& _other) const { return m_type == _other.m_type && m_data == _other.m_data; } bool operator!=(AssemblyItem const& _other) const { return !operator==(_other); } /// Less-than operator compatible with operator==. diff --git a/ControlFlowGraph.cpp b/ControlFlowGraph.cpp index 3566bdb17..41a53aa82 100644 --- a/ControlFlowGraph.cpp +++ b/ControlFlowGraph.cpp @@ -226,7 +226,10 @@ void ControlFlowGraph::gatherKnowledge() //@todo we might have to do something like incrementing the sequence number for each JUMPDEST assertThrow(!!workQueue.back().first, OptimizerException, ""); if (!m_blocks.count(workQueue.back().first)) + { + workQueue.pop_back(); continue; // too bad, we do not know the tag, probably an invalid jump + } BasicBlock& block = m_blocks.at(workQueue.back().first); KnownStatePointer state = workQueue.back().second; workQueue.pop_back(); @@ -257,10 +260,7 @@ void ControlFlowGraph::gatherKnowledge() ); state->feedItem(m_items.at(pc++)); - if (tags.empty() || std::any_of(tags.begin(), tags.end(), [&](u256 const& _tag) - { - return !m_blocks.count(BlockId(_tag)); - })) + if (tags.empty()) { if (!unknownJumpEncountered) {