diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 8588832fe..d70ef9fed 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -521,6 +521,7 @@ map Assembly::optimiseInternal( LinkerObject const& Assembly::assemble() const { + assertThrow(!m_invalid, AssemblyException, "Attempted to assemble invalid Assembly object."); // Return the already assembled object, if present. if (!m_assembledObject.bytecode.empty()) return m_assembledObject; diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index e82fee7dd..3b8c7e3a8 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -142,6 +142,9 @@ public: std::map const& _sourceIndices = std::map() ) const; + /// Mark this assembly as invalid. Calling ``assemble`` on it will throw. + void markAsInvalid() { m_invalid = true; } + protected: /// Does the same operations as @a optimise, but should only be applied to a sub and /// returns the replaced tags. Also takes an argument containing the tags of this assembly @@ -161,6 +164,7 @@ private: ); static std::string toStringInHex(u256 _value); + bool m_invalid = false; protected: /// 0 is reserved for exception unsigned m_usedTags = 1; diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 42622272c..d138968ba 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -111,6 +111,9 @@ public: virtual void appendImmutable(std::string const& _identifier) = 0; /// Appends an assignment to an immutable variable. virtual void appendImmutableAssignment(std::string const& _identifier) = 0; + + /// Mark this assembly as invalid. Any attempt to request bytecode from it should throw. + virtual void markAsInvalid() = 0; }; enum class IdentifierContext { LValue, RValue, VariableDeclaration }; diff --git a/libyul/backends/evm/AsmCodeGen.cpp b/libyul/backends/evm/AsmCodeGen.cpp index 8c6f672ab..8e245f99d 100644 --- a/libyul/backends/evm/AsmCodeGen.cpp +++ b/libyul/backends/evm/AsmCodeGen.cpp @@ -182,6 +182,11 @@ void EthAssemblyAdapter::appendImmutableAssignment(std::string const& _identifie m_assembly.appendImmutableAssignment(_identifier); } +void EthAssemblyAdapter::markAsInvalid() +{ + m_assembly.markAsInvalid(); +} + EthAssemblyAdapter::LabelID EthAssemblyAdapter::assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag) { u256 id = _tag.data(); diff --git a/libyul/backends/evm/AsmCodeGen.h b/libyul/backends/evm/AsmCodeGen.h index 6ff02009c..4933fbfd2 100644 --- a/libyul/backends/evm/AsmCodeGen.h +++ b/libyul/backends/evm/AsmCodeGen.h @@ -64,6 +64,8 @@ public: void appendImmutable(std::string const& _identifier) override; void appendImmutableAssignment(std::string const& _identifier) override; + void markAsInvalid() override; + private: static LabelID assemblyTagToIdentifier(evmasm::AssemblyItem const& _tag); void appendJumpInstruction(evmasm::Instruction _instruction, JumpType _jumpType); diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp index 7cf3d0662..0158e7bfa 100644 --- a/libyul/backends/evm/EVMAssembly.cpp +++ b/libyul/backends/evm/EVMAssembly.cpp @@ -156,6 +156,7 @@ void EVMAssembly::appendReturnsub(int _returns, int _stackDiffAfter) evmasm::LinkerObject EVMAssembly::finalize() { + yulAssert(!m_invalid, "Attempted to finalize invalid assembly object."); size_t bytecodeSize = m_bytecode.size(); for (auto const& ref: m_assemblySizePositions) updateReference(ref, assemblySizeReferenceSize, u256(bytecodeSize)); diff --git a/libyul/backends/evm/EVMAssembly.h b/libyul/backends/evm/EVMAssembly.h index 9ee974bbb..858ae3def 100644 --- a/libyul/backends/evm/EVMAssembly.h +++ b/libyul/backends/evm/EVMAssembly.h @@ -86,6 +86,8 @@ public: void appendImmutable(std::string const& _identifier) override; void appendImmutableAssignment(std::string const& _identifier) override; + void markAsInvalid() override { m_invalid = true; } + /// Resolves references inside the bytecode and returns the linker object. evmasm::LinkerObject finalize(); @@ -102,6 +104,7 @@ private: std::map m_labelPositions; std::map m_labelReferences; std::vector m_assemblySizePositions; + bool m_invalid = false; }; } diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 0287f585d..df8fb9343 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -237,6 +237,7 @@ void CodeTransform::stackError(StackTooDeepError _error, int _targetStackHeight) m_assembly.appendConstant(u256(0)); // Store error. m_stackErrors.emplace_back(std::move(_error)); + m_assembly.markAsInvalid(); } void CodeTransform::operator()(Assignment const& _assignment) @@ -448,11 +449,15 @@ void CodeTransform::operator()(FunctionDefinition const& _function) m_context ); subTransform(_function.body); - for (auto& stackError: subTransform.m_stackErrors) + if (!subTransform.m_stackErrors.empty()) { - if (stackError.functionName.empty()) - stackError.functionName = _function.name; - m_stackErrors.emplace_back(std::move(stackError)); + m_assembly.markAsInvalid(); + for (StackTooDeepError& stackError: subTransform.m_stackErrors) + { + if (stackError.functionName.empty()) + stackError.functionName = _function.name; + m_stackErrors.emplace_back(std::move(stackError)); + } } m_assembly.appendLabel(m_context->functionExitPoints.top().label); @@ -718,7 +723,7 @@ size_t CodeTransform::variableHeightDiff(Scope::Variable const& _var, YulString to_string(heightDiff - limit) + " slot(s) too deep inside the stack." ); - // TODO: maybe make this return something special that results in producing INVALID instead. + m_assembly.markAsInvalid(); return _forSwap ? 2 : 1; } return heightDiff; diff --git a/libyul/backends/evm/NoOutputAssembly.h b/libyul/backends/evm/NoOutputAssembly.h index ec7e5f2ec..a5bcecd2c 100644 --- a/libyul/backends/evm/NoOutputAssembly.h +++ b/libyul/backends/evm/NoOutputAssembly.h @@ -74,6 +74,8 @@ public: void appendImmutable(std::string const& _identifier) override; void appendImmutableAssignment(std::string const& _identifier) override; + void markAsInvalid() override {} + private: bool m_evm15 = false; ///< if true, switch to evm1.5 mode int m_stackHeight = 0;