diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp index a1dfd21c5..c1d61b887 100644 --- a/libevmasm/ConstantOptimiser.cpp +++ b/libevmasm/ConstantOptimiser.cpp @@ -232,6 +232,54 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value) } } +bool ComputeMethod::checkRepresentation(u256 const& _value) +{ + // This is a tiny EVM that can only evaluate some instructions. + vector stack; + for (AssemblyItem const& item: m_routine) + { + switch (item.type()) + { + case Operation: + { + if (stack.size() < size_t(item.arguments())) + return false; + u256* sp = &stack.back(); + switch (item.instruction()) + { + case Instruction::MUL: + sp[-1] = sp[0] * sp[-1]; + break; + case Instruction::EXP: + if (sp[-1] > 0xff) + return false; + sp[-1] = boost::multiprecision::pow(sp[0], unsigned(sp[-1])); + break; + case Instruction::ADD: + sp[-1] = sp[0] + sp[-1]; + break; + case Instruction::SUB: + sp[-1] = sp[0] - sp[-1]; + break; + case Instruction::NOT: + sp[0] = ~sp[0]; + break; + default: + return false; + } + stack.resize(stack.size() + item.deposit()); + break; + } + case Push: + stack.push_back(item.data()); + break; + default: + return false; + } + } + return stack.size() == 1 && stack.front() == _value; +} + bigint ComputeMethod::gasNeeded(AssemblyItems const& _routine) { size_t numExps = count(_routine.begin(), _routine.end(), Instruction::EXP); diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h index 4f12c49f8..8a37b3cbc 100644 --- a/libevmasm/ConstantOptimiser.h +++ b/libevmasm/ConstantOptimiser.h @@ -21,10 +21,13 @@ #pragma once -#include +#include + #include #include +#include + namespace dev { namespace eth @@ -130,6 +133,8 @@ public: ConstantOptimisationMethod(_params, _value) { m_routine = findRepresentation(m_value); + if (!checkRepresentation(m_value)) + BOOST_THROW_EXCEPTION(AssemblyException()); } virtual bigint gasNeeded() override { return gasNeeded(m_routine); } @@ -141,6 +146,8 @@ public: protected: /// Tries to recursively find a way to compute @a _value. AssemblyItems findRepresentation(u256 const& _value); + /// Recomputes the value from the calculated representation and checks for correctness. + bool checkRepresentation(u256 const& _value); bigint gasNeeded(AssemblyItems const& _routine); /// Counter for the complexity of optimization, will stop when it reaches zero.