From f113f8e4a0e459bf96048578c9c9de10f23be309 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 30 Apr 2019 15:02:52 +0200 Subject: [PATCH] Implement datasize, dataoffset and datacopy for yul interpreter. --- test/libyul/YulInterpreterTest.cpp | 3 +- test/libyul/YulInterpreterTest.h | 1 - test/libyul/yulInterpreterTests/datacopy.yul | 114 ++++++++++++++++++ .../libyul/yulInterpreterTests/dataoffset.yul | 16 +++ test/libyul/yulInterpreterTests/datasize.yul | 16 +++ test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp | 4 +- test/tools/ossfuzz/yulFuzzerCommon.cpp | 3 +- test/tools/ossfuzz/yulFuzzerCommon.h | 2 + test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp | 10 +- .../EVMInstructionInterpreter.cpp | 23 ++++ .../EVMInstructionInterpreter.h | 4 + test/tools/yulInterpreter/Interpreter.cpp | 17 ++- test/tools/yulInterpreter/Interpreter.h | 8 ++ test/tools/yulrun.cpp | 3 +- 14 files changed, 212 insertions(+), 12 deletions(-) create mode 100644 test/libyul/yulInterpreterTests/datacopy.yul create mode 100644 test/libyul/yulInterpreterTests/dataoffset.yul create mode 100644 test/libyul/yulInterpreterTests/datasize.yul diff --git a/test/libyul/YulInterpreterTest.cpp b/test/libyul/YulInterpreterTest.cpp index cfbb2ab08..dc1657e9a 100644 --- a/test/libyul/YulInterpreterTest.cpp +++ b/test/libyul/YulInterpreterTest.cpp @@ -132,7 +132,8 @@ string YulInterpreterTest::interpret() state.maxTraceSize = 10000; state.maxSteps = 10000; state.maxMemSize = 0x20000000; - Interpreter interpreter(state); + shared_ptr dialect(EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{})); + Interpreter interpreter(state, *dialect); try { interpreter(*m_ast); diff --git a/test/libyul/YulInterpreterTest.h b/test/libyul/YulInterpreterTest.h index 24daa2e2b..2d9b78fb1 100644 --- a/test/libyul/YulInterpreterTest.h +++ b/test/libyul/YulInterpreterTest.h @@ -30,7 +30,6 @@ namespace yul { struct AsmAnalysisInfo; struct Block; -struct Dialect; } namespace yul diff --git a/test/libyul/yulInterpreterTests/datacopy.yul b/test/libyul/yulInterpreterTests/datacopy.yul new file mode 100644 index 000000000..b083b1fe2 --- /dev/null +++ b/test/libyul/yulInterpreterTests/datacopy.yul @@ -0,0 +1,114 @@ +object "main" +{ + code { + datacopy(0, dataoffset("main"), datasize("main")) + datacopy(32, dataoffset("sub"), datasize("sub")) + sstore(0, mload(0)) + sstore(1, mload(32)) + } + object "sub" { code { sstore(0, 1) } } +} +// ---- +// Trace: +// MSTORE_AT_SIZE(0, 2916) +// MSTORE_AT_SIZE(32, 265) +// MLOAD_FROM_SIZE(0, 32) +// SSTORE(0, 0) +// MLOAD_FROM_SIZE(32, 32) +// SSTORE(1, 0) +// Memory dump: +// 0: 0000000000000000000000000000000000000000000000000000000000000000 +// 20: 0000000000000000000000000000000000000000000000000000000000000000 +// 40: 0000000000000000000000000000000000000000000000000000000000000000 +// 60: 0000000000000000000000000000000000000000000000000000000000000000 +// 80: 0000000000000000000000000000000000000000000000000000000000000000 +// a0: 0000000000000000000000000000000000000000000000000000000000000000 +// c0: 0000000000000000000000000000000000000000000000000000000000000000 +// e0: 0000000000000000000000000000000000000000000000000000000000000000 +// 100: 0000000000000000000000000000000000000000000000000000000000000000 +// 120: 0000000000000000000000000000000000000000000000000000000000000000 +// 140: 0000000000000000000000000000000000000000000000000000000000000000 +// 160: 0000000000000000000000000000000000000000000000000000000000000000 +// 180: 0000000000000000000000000000000000000000000000000000000000000000 +// 1a0: 0000000000000000000000000000000000000000000000000000000000000000 +// 1c0: 0000000000000000000000000000000000000000000000000000000000000000 +// 1e0: 0000000000000000000000000000000000000000000000000000000000000000 +// 200: 0000000000000000000000000000000000000000000000000000000000000000 +// 220: 0000000000000000000000000000000000000000000000000000000000000000 +// 240: 0000000000000000000000000000000000000000000000000000000000000000 +// 260: 0000000000000000000000000000000000000000000000000000000000000000 +// 280: 0000000000000000000000000000000000000000000000000000000000000000 +// 2a0: 0000000000000000000000000000000000000000000000000000000000000000 +// 2c0: 0000000000000000000000000000000000000000000000000000000000000000 +// 2e0: 0000000000000000000000000000000000000000000000000000000000000000 +// 300: 0000000000000000000000000000000000000000000000000000000000000000 +// 320: 0000000000000000000000000000000000000000000000000000000000000000 +// 340: 0000000000000000000000000000000000000000000000000000000000000000 +// 360: 0000000000000000000000000000000000000000000000000000000000000000 +// 380: 0000000000000000000000000000000000000000000000000000000000000000 +// 3a0: 0000000000000000000000000000000000000000000000000000000000000000 +// 3c0: 0000000000000000000000000000000000000000000000000000000000000000 +// 3e0: 0000000000000000000000000000000000000000000000000000000000000000 +// 400: 0000000000000000000000000000000000000000000000000000000000000000 +// 420: 0000000000000000000000000000000000000000000000000000000000000000 +// 440: 0000000000000000000000000000000000000000000000000000000000000000 +// 460: 0000000000000000000000000000000000000000000000000000000000000000 +// 480: 0000000000000000000000000000000000000000000000000000000000000000 +// 4a0: 0000000000000000000000000000000000000000000000000000000000000000 +// 4c0: 0000000000000000000000000000000000000000000000000000000000000000 +// 4e0: 0000000000000000000000000000000000000000000000000000000000000000 +// 500: 0000000000000000000000000000000000000000000000000000000000000000 +// 520: 0000000000000000000000000000000000000000000000000000000000000000 +// 540: 0000000000000000000000000000000000000000000000000000000000000000 +// 560: 0000000000000000000000000000000000000000000000000000000000000000 +// 580: 0000000000000000000000000000000000000000000000000000000000000000 +// 5a0: 0000000000000000000000000000000000000000000000000000000000000000 +// 5c0: 0000000000000000000000000000000000000000000000000000000000000000 +// 5e0: 0000000000000000000000000000000000000000000000000000000000000000 +// 600: 0000000000000000000000000000000000000000000000000000000000000000 +// 620: 0000000000000000000000000000000000000000000000000000000000000000 +// 640: 0000000000000000000000000000000000000000000000000000000000000000 +// 660: 0000000000000000000000000000000000000000000000000000000000000000 +// 680: 0000000000000000000000000000000000000000000000000000000000000000 +// 6a0: 0000000000000000000000000000000000000000000000000000000000000000 +// 6c0: 0000000000000000000000000000000000000000000000000000000000000000 +// 6e0: 0000000000000000000000000000000000000000000000000000000000000000 +// 700: 0000000000000000000000000000000000000000000000000000000000000000 +// 720: 0000000000000000000000000000000000000000000000000000000000000000 +// 740: 0000000000000000000000000000000000000000000000000000000000000000 +// 760: 0000000000000000000000000000000000000000000000000000000000000000 +// 780: 0000000000000000000000000000000000000000000000000000000000000000 +// 7a0: 0000000000000000000000000000000000000000000000000000000000000000 +// 7c0: 0000000000000000000000000000000000000000000000000000000000000000 +// 7e0: 0000000000000000000000000000000000000000000000000000000000000000 +// 800: 0000000000000000000000000000000000000000000000000000000000000000 +// 820: 0000000000000000000000000000000000000000000000000000000000000000 +// 840: 0000000000000000000000000000000000000000000000000000000000000000 +// 860: 0000000000000000000000000000000000000000000000000000000000000000 +// 880: 0000000000000000000000000000000000000000000000000000000000000000 +// 8a0: 0000000000000000000000000000000000000000000000000000000000000000 +// 8c0: 0000000000000000000000000000000000000000000000000000000000000000 +// 8e0: 0000000000000000000000000000000000000000000000000000000000000000 +// 900: 0000000000000000000000000000000000000000000000000000000000000000 +// 920: 0000000000000000000000000000000000000000000000000000000000000000 +// 940: 0000000000000000000000000000000000000000000000000000000000000000 +// 960: 0000000000000000000000000000000000000000000000000000000000000000 +// 980: 0000000000000000000000000000000000000000000000000000000000000000 +// 9a0: 0000000000000000000000000000000000000000000000000000000000000000 +// 9c0: 0000000000000000000000000000000000000000000000000000000000000000 +// 9e0: 0000000000000000000000000000000000000000000000000000000000000000 +// a00: 0000000000000000000000000000000000000000000000000000000000000000 +// a20: 0000000000000000000000000000000000000000000000000000000000000000 +// a40: 0000000000000000000000000000000000000000000000000000000000000000 +// a60: 0000000000000000000000000000000000000000000000000000000000000000 +// a80: 0000000000000000000000000000000000000000000000000000000000000000 +// aa0: 0000000000000000000000000000000000000000000000000000000000000000 +// ac0: 0000000000000000000000000000000000000000000000000000000000000000 +// ae0: 0000000000000000000000000000000000000000000000000000000000000000 +// b00: 0000000000000000000000000000000000000000000000000000000000000000 +// b20: 0000000000000000000000000000000000000000000000000000000000000000 +// b40: 0000000000000000000000000000000000000000000000000000000000000000 +// b60: 0000000000000000000000000000000000000000000000000000000000000000 +// Storage dump: +// 0000000000000000000000000000000000000000000000000000000000000000: 0000000000000000000000000000000000000000000000000000000000000000 +// 0000000000000000000000000000000000000000000000000000000000000001: 0000000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libyul/yulInterpreterTests/dataoffset.yul b/test/libyul/yulInterpreterTests/dataoffset.yul new file mode 100644 index 000000000..c4757624a --- /dev/null +++ b/test/libyul/yulInterpreterTests/dataoffset.yul @@ -0,0 +1,16 @@ +object "main" +{ + code { + sstore(0, dataoffset("main")) + sstore(1, dataoffset("sub")) + } + object "sub" { code { sstore(0, 1) } } +} +// ---- +// Trace: +// SSTORE(0, 110) +// SSTORE(1, 1804) +// Memory dump: +// Storage dump: +// 0000000000000000000000000000000000000000000000000000000000000000: 000000000000000000000000000000000000000000000000000000000000006e +// 0000000000000000000000000000000000000000000000000000000000000001: 000000000000000000000000000000000000000000000000000000000000070c diff --git a/test/libyul/yulInterpreterTests/datasize.yul b/test/libyul/yulInterpreterTests/datasize.yul new file mode 100644 index 000000000..a0400eea8 --- /dev/null +++ b/test/libyul/yulInterpreterTests/datasize.yul @@ -0,0 +1,16 @@ +object "main" +{ + code { + sstore(0, datasize("main")) + sstore(1, datasize("sub")) + } + object "sub" { code { sstore(0, 1) } } +} +// ---- +// Trace: +// SSTORE(0, 2916) +// SSTORE(1, 265) +// Memory dump: +// Storage dump: +// 0000000000000000000000000000000000000000000000000000000000000000: 0000000000000000000000000000000000000000000000000000000000000b64 +// 0000000000000000000000000000000000000000000000000000000000000001: 0000000000000000000000000000000000000000000000000000000000000109 diff --git a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp index 5f62e4c97..ebc0b9af3 100644 --- a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp @@ -80,7 +80,8 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) { yulFuzzerUtil::interpret( os1, - stack.parserResult()->code + stack.parserResult()->code, + *EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()) ); } catch (yul::test::StepLimitReached const&) @@ -97,6 +98,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) yulFuzzerUtil::interpret( os2, stack.parserResult()->code, + *EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()), (yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 1.5) ); } diff --git a/test/tools/ossfuzz/yulFuzzerCommon.cpp b/test/tools/ossfuzz/yulFuzzerCommon.cpp index 1a69d99ba..4d28554a2 100644 --- a/test/tools/ossfuzz/yulFuzzerCommon.cpp +++ b/test/tools/ossfuzz/yulFuzzerCommon.cpp @@ -23,6 +23,7 @@ using namespace yul::test::yul_fuzzer; void yulFuzzerUtil::interpret( ostream& _os, shared_ptr _ast, + Dialect const& _dialect, size_t _maxSteps, size_t _maxTraceSize, size_t _maxMemory @@ -32,7 +33,7 @@ void yulFuzzerUtil::interpret( state.maxTraceSize = _maxTraceSize; state.maxSteps = _maxSteps; state.maxMemSize = _maxMemory; - Interpreter interpreter(state); + Interpreter interpreter(state, _dialect); interpreter(*_ast); _os << "Trace:" << endl; for (auto const& line: interpreter.trace()) diff --git a/test/tools/ossfuzz/yulFuzzerCommon.h b/test/tools/ossfuzz/yulFuzzerCommon.h index b7db9494c..0392ef40c 100644 --- a/test/tools/ossfuzz/yulFuzzerCommon.h +++ b/test/tools/ossfuzz/yulFuzzerCommon.h @@ -15,6 +15,7 @@ along with solidity. If not, see . */ #include +#include namespace yul { @@ -27,6 +28,7 @@ struct yulFuzzerUtil static void interpret( std::ostream& _os, std::shared_ptr _ast, + Dialect const& _dialect, size_t _maxSteps = maxSteps, size_t _maxTraceSize = maxTraceSize, size_t _maxMemory = maxMemory diff --git a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp index 793effba3..44787d5a5 100644 --- a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp @@ -23,8 +23,9 @@ #include #include -#include +#include #include +#include #include @@ -76,7 +77,8 @@ DEFINE_PROTO_FUZZER(Function const& _input) { yulFuzzerUtil::interpret( os1, - stack.parserResult()->code + stack.parserResult()->code, + *EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()) ); } catch (yul::test::StepLimitReached const&) @@ -90,8 +92,10 @@ DEFINE_PROTO_FUZZER(Function const& _input) stack.optimize(); try { - yulFuzzerUtil::interpret(os2, + yulFuzzerUtil::interpret( + os2, stack.parserResult()->code, + *EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()), (yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 1.5) ); } diff --git a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp index 0d407eff6..4fea1b50c 100644 --- a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp +++ b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp @@ -444,6 +444,29 @@ u256 EVMInstructionInterpreter::eval( return 0; } +u256 EVMInstructionInterpreter::evalBuiltin(YulString _name, const std::vector& _arguments) +{ + if (_name == "datasize"_yulstring) + return u256(keccak256(h256(_arguments.at(0)))) & 0xfff; + else if (_name == "dataoffset"_yulstring) + return u256(keccak256(h256(_arguments.at(0) + 2))) & 0xfff; + else if (_name == "datacopy"_yulstring) + { + // This is identical to codecopy. + if (logMemoryWrite(_arguments.at(0), _arguments.at(2))) + copyZeroExtended( + m_state.memory, + m_state.code, + size_t(_arguments.at(0)), + size_t(_arguments.at(1) & size_t(-1)), + size_t(_arguments.at(2)) + ); + } + else + yulAssert(false, "Unknown builtin: " + _name.str()); + return 0; +} + bool EVMInstructionInterpreter::logMemoryRead(u256 const& _offset, u256 const& _size) { return logMemory(false, _offset, _size); diff --git a/test/tools/yulInterpreter/EVMInstructionInterpreter.h b/test/tools/yulInterpreter/EVMInstructionInterpreter.h index bd943b634..6d2ac0919 100644 --- a/test/tools/yulInterpreter/EVMInstructionInterpreter.h +++ b/test/tools/yulInterpreter/EVMInstructionInterpreter.h @@ -36,6 +36,7 @@ enum class Instruction: uint8_t; namespace yul { +class YulString; namespace test { @@ -66,7 +67,10 @@ public: explicit EVMInstructionInterpreter(InterpreterState& _state): m_state(_state) {} + /// Evaluate instruction dev::u256 eval(dev::eth::Instruction _instruction, std::vector const& _arguments); + /// Evaluate builtin function + dev::u256 evalBuiltin(YulString _name, std::vector const& _arguments); private: /// Record a memory read in the trace. Also updates m_state.msize diff --git a/test/tools/yulInterpreter/Interpreter.cpp b/test/tools/yulInterpreter/Interpreter.cpp index 1876da368..f63a73cda 100644 --- a/test/tools/yulInterpreter/Interpreter.cpp +++ b/test/tools/yulInterpreter/Interpreter.cpp @@ -23,7 +23,9 @@ #include #include +#include #include +#include #include @@ -157,14 +159,14 @@ void Interpreter::operator()(Block const& _block) u256 Interpreter::evaluate(Expression const& _expression) { - ExpressionEvaluator ev(m_state, m_variables, m_functions); + ExpressionEvaluator ev(m_state, m_dialect, m_variables, m_functions); ev.visit(_expression); return ev.value(); } vector Interpreter::evaluateMulti(Expression const& _expression) { - ExpressionEvaluator ev(m_state, m_variables, m_functions); + ExpressionEvaluator ev(m_state, m_dialect, m_variables, m_functions); ev.visit(_expression); return ev.values(); } @@ -204,9 +206,16 @@ void ExpressionEvaluator::operator()(FunctionalInstruction const& _instr) void ExpressionEvaluator::operator()(FunctionCall const& _funCall) { - solAssert(m_functions.count(_funCall.functionName.name), ""); evaluateArgs(_funCall.arguments); + if (dynamic_cast(&m_dialect) && m_dialect.builtin(_funCall.functionName.name)) + { + EVMInstructionInterpreter interpreter(m_state); + setValue(interpreter.evalBuiltin(_funCall.functionName.name, values())); + return; + } + + solAssert(m_functions.count(_funCall.functionName.name), ""); FunctionDefinition const& fun = *m_functions.at(_funCall.functionName.name); solAssert(m_values.size() == fun.parameters.size(), ""); map variables; @@ -217,7 +226,7 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall) // TODO function name lookup could be a little more efficient, // we have to copy the list here. - Interpreter interpreter(m_state, variables, m_functions); + Interpreter interpreter(m_state, m_dialect, variables, m_functions); interpreter(fun.body); m_values.clear(); diff --git a/test/tools/yulInterpreter/Interpreter.h b/test/tools/yulInterpreter/Interpreter.h index 7d6eb08a3..cf449a017 100644 --- a/test/tools/yulInterpreter/Interpreter.h +++ b/test/tools/yulInterpreter/Interpreter.h @@ -32,6 +32,8 @@ namespace yul { +struct Dialect; + namespace test { @@ -100,9 +102,11 @@ class Interpreter: public ASTWalker public: Interpreter( InterpreterState& _state, + Dialect const& _dialect, std::map _variables = {}, std::map _functions = {} ): + m_dialect(_dialect), m_state(_state), m_variables(std::move(_variables)), m_functions(std::move(_functions)) @@ -133,6 +137,7 @@ private: /// Unregisters variables. void closeScope(); + Dialect const& m_dialect; InterpreterState& m_state; /// Values of variables. std::map m_variables; @@ -150,10 +155,12 @@ class ExpressionEvaluator: public ASTWalker public: ExpressionEvaluator( InterpreterState& _state, + Dialect const& _dialect, std::map const& _variables, std::map const& _functions ): m_state(_state), + m_dialect(_dialect), m_variables(_variables), m_functions(_functions) {} @@ -176,6 +183,7 @@ private: void evaluateArgs(std::vector const& _expr); InterpreterState& m_state; + Dialect const& m_dialect; /// Values of variables. std::map const& m_variables; /// Meanings of functions. diff --git a/test/tools/yulrun.cpp b/test/tools/yulrun.cpp index c1461d61e..2e87e44f8 100644 --- a/test/tools/yulrun.cpp +++ b/test/tools/yulrun.cpp @@ -88,7 +88,8 @@ void interpret(string const& _source) InterpreterState state; state.maxTraceSize = 10000; state.maxMemSize = 0x20000000; - Interpreter interpreter(state); + shared_ptr dialect(EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{})); + Interpreter interpreter(state, *dialect); try { interpreter(*ast);