Yul interpreter: Limit nesting level

This commit is contained in:
Bhargava Shastry
2020-12-03 12:21:08 +01:00
parent 52c1b75f72
commit 24f0f3bb16
6 changed files with 53 additions and 11 deletions
+7 -1
View File
@@ -27,12 +27,14 @@ yulFuzzerUtil::TerminationReason yulFuzzerUtil::interpret(
shared_ptr<yul::Block> _ast,
Dialect const& _dialect,
size_t _maxSteps,
size_t _maxTraceSize
size_t _maxTraceSize,
size_t _maxExprNesting
)
{
InterpreterState state;
state.maxTraceSize = _maxTraceSize;
state.maxSteps = _maxSteps;
state.maxExprNesting = _maxExprNesting;
// Add 64 bytes of pseudo-randomly generated calldata so that
// calldata opcodes perform non trivial work.
state.calldata = {
@@ -59,6 +61,10 @@ yulFuzzerUtil::TerminationReason yulFuzzerUtil::interpret(
{
reason = TerminationReason::TraceLimitReached;
}
catch (ExpressionNestingLimitReached const&)
{
reason = TerminationReason::ExpresionNestingLimitReached;
}
catch (ExplicitlyTerminated const&)
{
reason = TerminationReason::ExplicitlyTerminated;
+4 -1
View File
@@ -28,6 +28,7 @@ struct yulFuzzerUtil
ExplicitlyTerminated,
StepLimitReached,
TraceLimitReached,
ExpresionNestingLimitReached,
None
};
@@ -36,10 +37,12 @@ struct yulFuzzerUtil
std::shared_ptr<yul::Block> _ast,
Dialect const& _dialect,
size_t _maxSteps = maxSteps,
size_t _maxTraceSize = maxTraceSize
size_t _maxTraceSize = maxTraceSize,
size_t _maxExprNesting = maxExprNesting
);
static size_t constexpr maxSteps = 100;
static size_t constexpr maxTraceSize = 75;
static size_t constexpr maxExprNesting = 60;
};
}
+16 -9
View File
@@ -91,22 +91,29 @@ DEFINE_PROTO_FUZZER(Program const& _input)
ostringstream os1;
ostringstream os2;
yulFuzzerUtil::interpret(
os1,
stack.parserResult()->code,
EVMDialect::strictAssemblyForEVMObjects(version)
);
stack.optimize();
yulFuzzerUtil::TerminationReason termReason = yulFuzzerUtil::interpret(
os2,
os1,
stack.parserResult()->code,
EVMDialect::strictAssemblyForEVMObjects(version)
);
if (
termReason == yulFuzzerUtil::TerminationReason::StepLimitReached ||
termReason == yulFuzzerUtil::TerminationReason::TraceLimitReached
termReason == yulFuzzerUtil::TerminationReason::TraceLimitReached ||
termReason == yulFuzzerUtil::TerminationReason::ExpresionNestingLimitReached
)
return;
stack.optimize();
termReason = yulFuzzerUtil::interpret(
os2,
stack.parserResult()->code,
EVMDialect::strictAssemblyForEVMObjects(version)
);
if (
termReason == yulFuzzerUtil::TerminationReason::StepLimitReached ||
termReason == yulFuzzerUtil::TerminationReason::TraceLimitReached ||
termReason == yulFuzzerUtil::TerminationReason::ExpresionNestingLimitReached
)
return;
+13
View File
@@ -247,6 +247,7 @@ void Interpreter::incrementStep()
void ExpressionEvaluator::operator()(Literal const& _literal)
{
incrementStep();
static YulString const trueString("true");
static YulString const falseString("false");
@@ -256,6 +257,7 @@ void ExpressionEvaluator::operator()(Literal const& _literal)
void ExpressionEvaluator::operator()(Identifier const& _identifier)
{
solAssert(m_variables.count(_identifier.name), "");
incrementStep();
setValue(m_variables.at(_identifier.name));
}
@@ -326,6 +328,7 @@ void ExpressionEvaluator::evaluateArgs(
vector<optional<LiteralKind>> const* _literalArguments
)
{
incrementStep();
vector<u256> values;
size_t i = 0;
/// Function arguments are evaluated in reverse.
@@ -341,3 +344,13 @@ void ExpressionEvaluator::evaluateArgs(
m_values = std::move(values);
std::reverse(m_values.begin(), m_values.end());
}
void ExpressionEvaluator::incrementStep()
{
m_nestingLevel++;
if (m_state.maxExprNesting > 0 && m_nestingLevel > m_state.maxExprNesting)
{
m_state.trace.emplace_back("Maximum expression nesting level reached.");
throw ExpressionNestingLimitReached();
}
}
+12
View File
@@ -55,6 +55,10 @@ class TraceLimitReached: public InterpreterTerminatedGeneric
{
};
class ExpressionNestingLimitReached: public InterpreterTerminatedGeneric
{
};
enum class ControlFlowState
{
Default,
@@ -92,6 +96,7 @@ struct InterpreterState
size_t maxTraceSize = 0;
size_t maxSteps = 0;
size_t numSteps = 0;
size_t maxExprNesting = 0;
ControlFlowState controlFlowState = ControlFlowState::Default;
void dumpTraceAndState(std::ostream& _out) const;
@@ -202,6 +207,11 @@ private:
std::vector<std::optional<LiteralKind>> const* _literalArguments
);
/// Increment evaluation count, throwing exception if the
/// nesting level is beyond the upper bound configured in
/// the interpreter state.
void incrementStep();
InterpreterState& m_state;
Dialect const& m_dialect;
/// Values of variables.
@@ -209,6 +219,8 @@ private:
Scope& m_scope;
/// Current value of the expression
std::vector<u256> m_values;
/// Current expression nesting level
unsigned m_nestingLevel = 0;
};
}