Implement datasize, dataoffset and datacopy for yul interpreter.

This commit is contained in:
chriseth
2019-05-06 16:59:47 +02:00
committed by Bhargava Shastry
parent e99efec085
commit f113f8e4a0
14 changed files with 212 additions and 12 deletions
@@ -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)
);
}
+2 -1
View File
@@ -23,6 +23,7 @@ using namespace yul::test::yul_fuzzer;
void yulFuzzerUtil::interpret(
ostream& _os,
shared_ptr<yul::Block> _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())
+2
View File
@@ -15,6 +15,7 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
#include <test/tools/yulInterpreter/Interpreter.h>
#include <libyul/backends/evm/EVMDialect.h>
namespace yul
{
@@ -27,6 +28,7 @@ struct yulFuzzerUtil
static void interpret(
std::ostream& _os,
std::shared_ptr<yul::Block> _ast,
Dialect const& _dialect,
size_t _maxSteps = maxSteps,
size_t _maxTraceSize = maxTraceSize,
size_t _maxMemory = maxMemory
+7 -3
View File
@@ -23,8 +23,9 @@
#include <src/libfuzzer/libfuzzer_macro.h>
#include <libyul/AssemblyStack.h>
#include <liblangutil/EVMVersion.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/Exceptions.h>
#include <liblangutil/EVMVersion.h>
#include <test/tools/ossfuzz/yulFuzzerCommon.h>
@@ -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)
);
}
@@ -444,6 +444,29 @@ u256 EVMInstructionInterpreter::eval(
return 0;
}
u256 EVMInstructionInterpreter::evalBuiltin(YulString _name, const std::vector<u256>& _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);
@@ -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<dev::u256> const& _arguments);
/// Evaluate builtin function
dev::u256 evalBuiltin(YulString _name, std::vector<dev::u256> const& _arguments);
private:
/// Record a memory read in the trace. Also updates m_state.msize
+13 -4
View File
@@ -23,7 +23,9 @@
#include <test/tools/yulInterpreter/EVMInstructionInterpreter.h>
#include <libyul/AsmData.h>
#include <libyul/Dialect.h>
#include <libyul/Utilities.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <liblangutil/Exceptions.h>
@@ -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<u256> 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<EVMDialect const*>(&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<YulString, u256> 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();
+8
View File
@@ -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<YulString, dev::u256> _variables = {},
std::map<YulString, FunctionDefinition const*> _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<YulString, dev::u256> m_variables;
@@ -150,10 +155,12 @@ class ExpressionEvaluator: public ASTWalker
public:
ExpressionEvaluator(
InterpreterState& _state,
Dialect const& _dialect,
std::map<YulString, dev::u256> const& _variables,
std::map<YulString, FunctionDefinition const*> const& _functions
):
m_state(_state),
m_dialect(_dialect),
m_variables(_variables),
m_functions(_functions)
{}
@@ -176,6 +183,7 @@ private:
void evaluateArgs(std::vector<Expression> const& _expr);
InterpreterState& m_state;
Dialect const& m_dialect;
/// Values of variables.
std::map<YulString, dev::u256> const& m_variables;
/// Meanings of functions.
+2 -1
View File
@@ -88,7 +88,8 @@ void interpret(string const& _source)
InterpreterState state;
state.maxTraceSize = 10000;
state.maxMemSize = 0x20000000;
Interpreter interpreter(state);
shared_ptr<Dialect> dialect(EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{}));
Interpreter interpreter(state, *dialect);
try
{
interpreter(*ast);