mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6398 from ethereum/yulInterpreter-maxSteps
yulInterpreter: Add timeout based on the number of interpreted statem…
This commit is contained in:
commit
e75f99b2bd
@ -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&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,9 +76,26 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size)
|
|||||||
|
|
||||||
ostringstream os1;
|
ostringstream os1;
|
||||||
ostringstream os2;
|
ostringstream os2;
|
||||||
yulFuzzerUtil::interpret(os1, stack.parserResult()->code);
|
try
|
||||||
|
{
|
||||||
|
yulFuzzerUtil::interpret(os1, stack.parserResult()->code);
|
||||||
|
}
|
||||||
|
catch (yul::test::StepLimitReached const&)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (yul::test::InterpreterTerminatedGeneric const&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
stack.optimize();
|
stack.optimize();
|
||||||
yulFuzzerUtil::interpret(os2, stack.parserResult()->code);
|
try
|
||||||
|
{
|
||||||
|
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.");
|
||||||
|
@ -24,17 +24,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -72,9 +72,26 @@ DEFINE_PROTO_FUZZER(Function const& _input)
|
|||||||
|
|
||||||
ostringstream os1;
|
ostringstream os1;
|
||||||
ostringstream os2;
|
ostringstream os2;
|
||||||
yulFuzzerUtil::interpret(os1, stack.parserResult()->code);
|
try
|
||||||
|
{
|
||||||
|
yulFuzzerUtil::interpret(os1, stack.parserResult()->code);
|
||||||
|
}
|
||||||
|
catch (yul::test::StepLimitReached const&)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (yul::test::InterpreterTerminatedGeneric const&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
stack.optimize();
|
stack.optimize();
|
||||||
yulFuzzerUtil::interpret(os2, stack.parserResult()->code);
|
try
|
||||||
|
{
|
||||||
|
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.");
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ void interpret(string const& _source)
|
|||||||
{
|
{
|
||||||
interpreter(*ast);
|
interpreter(*ast);
|
||||||
}
|
}
|
||||||
catch (InterpreterTerminated const&)
|
catch (InterpreterTerminatedGeneric const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user