aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Beregszaszi <alex@rtfs.hu>2017-04-27 23:26:08 +0800
committerGitHub <noreply@github.com>2017-04-27 23:26:08 +0800
commit2c8b77006255b15743efd0b54964227bccc07c57 (patch)
tree17cb0166bb6290aeb125d07e4247e57d58203b64
parent122dc65b3608b368897701dbdebc689bc614933f (diff)
parent0e91b8fb98ee942aeb668ef5ff1c6e40c52a7a2e (diff)
downloaddexon-solidity-2c8b77006255b15743efd0b54964227bccc07c57.tar.gz
dexon-solidity-2c8b77006255b15743efd0b54964227bccc07c57.tar.zst
dexon-solidity-2c8b77006255b15743efd0b54964227bccc07c57.zip
Merge pull request #2187 from ethereum/testOptimizer
Add recomputation check for number representation.
-rw-r--r--libevmasm/ConstantOptimiser.cpp48
-rw-r--r--libevmasm/ConstantOptimiser.h13
2 files changed, 60 insertions, 1 deletions
diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp
index a1dfd21c..d2ed4faf 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, AssemblyItems const& _routine)
+{
+ // This is a tiny EVM that can only evaluate some instructions.
+ vector<u256> stack;
+ for (AssemblyItem const& item: _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 4f12c49f..85bdabac 100644
--- a/libevmasm/ConstantOptimiser.h
+++ b/libevmasm/ConstantOptimiser.h
@@ -21,10 +21,14 @@
#pragma once
-#include <vector>
+#include <libevmasm/Exceptions.h>
+
+#include <libdevcore/Assertions.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonIO.h>
+#include <vector>
+
namespace dev
{
namespace eth
@@ -130,6 +134,11 @@ public:
ConstantOptimisationMethod(_params, _value)
{
m_routine = findRepresentation(m_value);
+ assertThrow(
+ checkRepresentation(m_value, m_routine),
+ OptimizerException,
+ "Invalid constant expression created."
+ );
}
virtual bigint gasNeeded() override { return gasNeeded(m_routine); }
@@ -141,6 +150,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, AssemblyItems const& _routine);
bigint gasNeeded(AssemblyItems const& _routine);
/// Counter for the complexity of optimization, will stop when it reaches zero.