Merge pull request #6398 from ethereum/yulInterpreter-maxSteps

yulInterpreter: Add timeout based on the number of interpreted statem…
This commit is contained in:
chriseth 2019-04-04 13:19:07 +02:00 committed by GitHub
commit e75f99b2bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 65 additions and 24 deletions

View File

@ -130,12 +130,14 @@ string YulInterpreterTest::interpret()
{ {
InterpreterState state; InterpreterState state;
state.maxTraceSize = 10000; state.maxTraceSize = 10000;
state.maxSteps = 10000;
state.maxMemSize = 0x20000000;
Interpreter interpreter(state); Interpreter interpreter(state);
try try
{ {
interpreter(*m_ast); interpreter(*m_ast);
} }
catch (InterpreterTerminated const&) catch (InterpreterTerminatedGeneric const&)
{ {
} }

View File

@ -76,9 +76,26 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size)
ostringstream os1; ostringstream os1;
ostringstream os2; ostringstream os2;
try
{
yulFuzzerUtil::interpret(os1, stack.parserResult()->code); yulFuzzerUtil::interpret(os1, stack.parserResult()->code);
}
catch (yul::test::StepLimitReached const&)
{
return 0;
}
catch (yul::test::InterpreterTerminatedGeneric const&)
{
}
stack.optimize(); stack.optimize();
try
{
yulFuzzerUtil::interpret(os2, stack.parserResult()->code); yulFuzzerUtil::interpret(os2, stack.parserResult()->code);
}
catch (yul::test::InterpreterTerminatedGeneric const&)
{
}
bool isTraceEq = (os1.str() == os2.str()); bool isTraceEq = (os1.str() == os2.str());
yulAssert(isTraceEq, "Interpreted traces for optimized and unoptimized code differ."); yulAssert(isTraceEq, "Interpreted traces for optimized and unoptimized code differ.");

View File

@ -24,16 +24,9 @@ void yulFuzzerUtil::interpret(ostream& _os, shared_ptr<yul::Block> _ast)
{ {
InterpreterState state; InterpreterState state;
state.maxTraceSize = 75; state.maxTraceSize = 75;
state.maxSteps = 10000; state.maxSteps = 100;
Interpreter interpreter(state); Interpreter interpreter(state);
try
{
interpreter(*_ast); interpreter(*_ast);
}
catch (InterpreterTerminated const&)
{
}
_os << "Trace:" << endl; _os << "Trace:" << endl;
for (auto const& line: interpreter.trace()) for (auto const& line: interpreter.trace())
_os << " " << line << endl; _os << " " << line << endl;

View File

@ -72,9 +72,26 @@ DEFINE_PROTO_FUZZER(Function const& _input)
ostringstream os1; ostringstream os1;
ostringstream os2; ostringstream os2;
try
{
yulFuzzerUtil::interpret(os1, stack.parserResult()->code); yulFuzzerUtil::interpret(os1, stack.parserResult()->code);
}
catch (yul::test::StepLimitReached const&)
{
return;
}
catch (yul::test::InterpreterTerminatedGeneric const&)
{
}
stack.optimize(); stack.optimize();
try
{
yulFuzzerUtil::interpret(os2, stack.parserResult()->code); yulFuzzerUtil::interpret(os2, stack.parserResult()->code);
}
catch (yul::test::InterpreterTerminatedGeneric const&)
{
}
bool isTraceEq = (os1.str() == os2.str()); bool isTraceEq = (os1.str() == os2.str());
yulAssert(isTraceEq, "Interpreted traces for optimized and unoptimized code differ."); yulAssert(isTraceEq, "Interpreted traces for optimized and unoptimized code differ.");

View File

@ -106,7 +106,7 @@ u256 EVMInstructionInterpreter::eval(
switch (_instruction) switch (_instruction)
{ {
case Instruction::STOP: case Instruction::STOP:
throw InterpreterTerminated(); throw ExplicitlyTerminated();
// --------------- arithmetic --------------- // --------------- arithmetic ---------------
case Instruction::ADD: case Instruction::ADD:
return arg[0] + arg[1]; return arg[0] + arg[1];
@ -342,18 +342,18 @@ u256 EVMInstructionInterpreter::eval(
if (logMemoryRead(arg[0], arg[1])) if (logMemoryRead(arg[0], arg[1]))
data = bytesConstRef(m_state.memory.data() + size_t(arg[0]), size_t(arg[1])).toBytes(); data = bytesConstRef(m_state.memory.data() + size_t(arg[0]), size_t(arg[1])).toBytes();
logTrace(_instruction, arg, data); logTrace(_instruction, arg, data);
throw InterpreterTerminated(); throw ExplicitlyTerminated();
} }
case Instruction::REVERT: case Instruction::REVERT:
logMemoryRead(arg[0], arg[1]); logMemoryRead(arg[0], arg[1]);
logTrace(_instruction, arg); logTrace(_instruction, arg);
throw InterpreterTerminated(); throw ExplicitlyTerminated();
case Instruction::INVALID: case Instruction::INVALID:
logTrace(_instruction); logTrace(_instruction);
throw InterpreterTerminated(); throw ExplicitlyTerminated();
case Instruction::SELFDESTRUCT: case Instruction::SELFDESTRUCT:
logTrace(_instruction, arg); logTrace(_instruction, arg);
throw InterpreterTerminated(); throw ExplicitlyTerminated();
case Instruction::POP: case Instruction::POP:
break; break;
// --------------- invalid in strict assembly --------------- // --------------- invalid in strict assembly ---------------
@ -492,6 +492,6 @@ void EVMInstructionInterpreter::logTrace(std::string const& _pseudoInstruction,
if (m_state.maxTraceSize > 0 && m_state.trace.size() >= m_state.maxTraceSize) if (m_state.maxTraceSize > 0 && m_state.trace.size() >= m_state.maxTraceSize)
{ {
m_state.trace.emplace_back("Trace size limit reached."); m_state.trace.emplace_back("Trace size limit reached.");
throw InterpreterTerminated(); throw TraceLimitReached();
} }
} }

View File

@ -132,7 +132,7 @@ void Interpreter::operator()(Block const& _block)
if (m_state.maxSteps > 0 && m_state.numSteps >= m_state.maxSteps) if (m_state.maxSteps > 0 && m_state.numSteps >= m_state.maxSteps)
{ {
m_state.trace.emplace_back("Interpreter execution step limit reached."); m_state.trace.emplace_back("Interpreter execution step limit reached.");
throw InterpreterTerminated(); throw StepLimitReached();
} }
openScope(); openScope();
// Register functions. // Register functions.

View File

@ -35,7 +35,19 @@ namespace yul
namespace test namespace test
{ {
class InterpreterTerminated: dev::Exception class InterpreterTerminatedGeneric: public dev::Exception
{
};
class ExplicitlyTerminated: public InterpreterTerminatedGeneric
{
};
class StepLimitReached: public InterpreterTerminatedGeneric
{
};
class TraceLimitReached: public InterpreterTerminatedGeneric
{ {
}; };

View File

@ -96,7 +96,7 @@ void interpret(string const& _source)
{ {
interpreter(*ast); interpreter(*ast);
} }
catch (InterpreterTerminated const&) catch (InterpreterTerminatedGeneric const&)
{ {
} }