mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10487 from ethereum/yul-interpreter-expression-nesting-level
Yul interpreter: Introduce expression evaluation maximum nesting depth
This commit is contained in:
commit
83fc7d3f7d
@ -102,6 +102,7 @@ string EwasmTranslationTest::interpret()
|
|||||||
InterpreterState state;
|
InterpreterState state;
|
||||||
state.maxTraceSize = 10000;
|
state.maxTraceSize = 10000;
|
||||||
state.maxSteps = 1000000;
|
state.maxSteps = 1000000;
|
||||||
|
state.maxExprNesting = 64;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Interpreter::run(state, WasmDialect{}, *m_object->code);
|
Interpreter::run(state, WasmDialect{}, *m_object->code);
|
||||||
|
@ -89,6 +89,7 @@ string YulInterpreterTest::interpret()
|
|||||||
InterpreterState state;
|
InterpreterState state;
|
||||||
state.maxTraceSize = 32;
|
state.maxTraceSize = 32;
|
||||||
state.maxSteps = 512;
|
state.maxSteps = 512;
|
||||||
|
state.maxExprNesting = 64;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Interpreter::run(state, EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{}), *m_ast);
|
Interpreter::run(state, EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{}), *m_ast);
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
function f(x) -> y
|
||||||
|
{
|
||||||
|
// 32 nested additions are computed in
|
||||||
|
// exactly 66 expression evaluation steps
|
||||||
|
y := add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,x))))))))))))))))))))))))))))))))
|
||||||
|
}
|
||||||
|
mstore(0,f(0))
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Trace:
|
||||||
|
// Maximum expression nesting level reached.
|
||||||
|
// Memory dump:
|
||||||
|
// Storage dump:
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
function f(x) -> y
|
||||||
|
{
|
||||||
|
// 31 nested additions are computed in
|
||||||
|
// exactly 64 expression evaluation steps
|
||||||
|
y := add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,add(0x1,x)))))))))))))))))))))))))))))))
|
||||||
|
}
|
||||||
|
mstore(0,f(0))
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Trace:
|
||||||
|
// Memory dump:
|
||||||
|
// 0: 000000000000000000000000000000000000000000000000000000000000001f
|
||||||
|
// Storage dump:
|
@ -27,12 +27,14 @@ yulFuzzerUtil::TerminationReason yulFuzzerUtil::interpret(
|
|||||||
shared_ptr<yul::Block> _ast,
|
shared_ptr<yul::Block> _ast,
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
size_t _maxSteps,
|
size_t _maxSteps,
|
||||||
size_t _maxTraceSize
|
size_t _maxTraceSize,
|
||||||
|
size_t _maxExprNesting
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
InterpreterState state;
|
InterpreterState state;
|
||||||
state.maxTraceSize = _maxTraceSize;
|
state.maxTraceSize = _maxTraceSize;
|
||||||
state.maxSteps = _maxSteps;
|
state.maxSteps = _maxSteps;
|
||||||
|
state.maxExprNesting = _maxExprNesting;
|
||||||
// Add 64 bytes of pseudo-randomly generated calldata so that
|
// Add 64 bytes of pseudo-randomly generated calldata so that
|
||||||
// calldata opcodes perform non trivial work.
|
// calldata opcodes perform non trivial work.
|
||||||
state.calldata = {
|
state.calldata = {
|
||||||
@ -59,6 +61,10 @@ yulFuzzerUtil::TerminationReason yulFuzzerUtil::interpret(
|
|||||||
{
|
{
|
||||||
reason = TerminationReason::TraceLimitReached;
|
reason = TerminationReason::TraceLimitReached;
|
||||||
}
|
}
|
||||||
|
catch (ExpressionNestingLimitReached const&)
|
||||||
|
{
|
||||||
|
reason = TerminationReason::ExpresionNestingLimitReached;
|
||||||
|
}
|
||||||
catch (ExplicitlyTerminated const&)
|
catch (ExplicitlyTerminated const&)
|
||||||
{
|
{
|
||||||
reason = TerminationReason::ExplicitlyTerminated;
|
reason = TerminationReason::ExplicitlyTerminated;
|
||||||
|
@ -28,6 +28,7 @@ struct yulFuzzerUtil
|
|||||||
ExplicitlyTerminated,
|
ExplicitlyTerminated,
|
||||||
StepLimitReached,
|
StepLimitReached,
|
||||||
TraceLimitReached,
|
TraceLimitReached,
|
||||||
|
ExpresionNestingLimitReached,
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,10 +37,12 @@ struct yulFuzzerUtil
|
|||||||
std::shared_ptr<yul::Block> _ast,
|
std::shared_ptr<yul::Block> _ast,
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
size_t _maxSteps = maxSteps,
|
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 maxSteps = 100;
|
||||||
static size_t constexpr maxTraceSize = 75;
|
static size_t constexpr maxTraceSize = 75;
|
||||||
|
static size_t constexpr maxExprNesting = 64;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,8 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
termReason == yulFuzzerUtil::TerminationReason::StepLimitReached ||
|
termReason == yulFuzzerUtil::TerminationReason::StepLimitReached ||
|
||||||
termReason == yulFuzzerUtil::TerminationReason::TraceLimitReached
|
termReason == yulFuzzerUtil::TerminationReason::TraceLimitReached ||
|
||||||
|
termReason == yulFuzzerUtil::TerminationReason::ExpresionNestingLimitReached
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -109,10 +110,10 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
|||||||
stack.parserResult()->code,
|
stack.parserResult()->code,
|
||||||
EVMDialect::strictAssemblyForEVMObjects(version)
|
EVMDialect::strictAssemblyForEVMObjects(version)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
termReason == yulFuzzerUtil::TerminationReason::StepLimitReached ||
|
termReason == yulFuzzerUtil::TerminationReason::StepLimitReached ||
|
||||||
termReason == yulFuzzerUtil::TerminationReason::TraceLimitReached
|
termReason == yulFuzzerUtil::TerminationReason::TraceLimitReached ||
|
||||||
|
termReason == yulFuzzerUtil::TerminationReason::ExpresionNestingLimitReached
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -247,6 +247,7 @@ void Interpreter::incrementStep()
|
|||||||
|
|
||||||
void ExpressionEvaluator::operator()(Literal const& _literal)
|
void ExpressionEvaluator::operator()(Literal const& _literal)
|
||||||
{
|
{
|
||||||
|
incrementStep();
|
||||||
static YulString const trueString("true");
|
static YulString const trueString("true");
|
||||||
static YulString const falseString("false");
|
static YulString const falseString("false");
|
||||||
|
|
||||||
@ -256,6 +257,7 @@ void ExpressionEvaluator::operator()(Literal const& _literal)
|
|||||||
void ExpressionEvaluator::operator()(Identifier const& _identifier)
|
void ExpressionEvaluator::operator()(Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
solAssert(m_variables.count(_identifier.name), "");
|
solAssert(m_variables.count(_identifier.name), "");
|
||||||
|
incrementStep();
|
||||||
setValue(m_variables.at(_identifier.name));
|
setValue(m_variables.at(_identifier.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,6 +328,7 @@ void ExpressionEvaluator::evaluateArgs(
|
|||||||
vector<optional<LiteralKind>> const* _literalArguments
|
vector<optional<LiteralKind>> const* _literalArguments
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
incrementStep();
|
||||||
vector<u256> values;
|
vector<u256> values;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
/// Function arguments are evaluated in reverse.
|
/// Function arguments are evaluated in reverse.
|
||||||
@ -341,3 +344,13 @@ void ExpressionEvaluator::evaluateArgs(
|
|||||||
m_values = std::move(values);
|
m_values = std::move(values);
|
||||||
std::reverse(m_values.begin(), m_values.end());
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -55,6 +55,10 @@ class TraceLimitReached: public InterpreterTerminatedGeneric
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExpressionNestingLimitReached: public InterpreterTerminatedGeneric
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
enum class ControlFlowState
|
enum class ControlFlowState
|
||||||
{
|
{
|
||||||
Default,
|
Default,
|
||||||
@ -92,6 +96,7 @@ struct InterpreterState
|
|||||||
size_t maxTraceSize = 0;
|
size_t maxTraceSize = 0;
|
||||||
size_t maxSteps = 0;
|
size_t maxSteps = 0;
|
||||||
size_t numSteps = 0;
|
size_t numSteps = 0;
|
||||||
|
size_t maxExprNesting = 0;
|
||||||
ControlFlowState controlFlowState = ControlFlowState::Default;
|
ControlFlowState controlFlowState = ControlFlowState::Default;
|
||||||
|
|
||||||
void dumpTraceAndState(std::ostream& _out) const;
|
void dumpTraceAndState(std::ostream& _out) const;
|
||||||
@ -202,6 +207,11 @@ private:
|
|||||||
std::vector<std::optional<LiteralKind>> const* _literalArguments
|
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;
|
InterpreterState& m_state;
|
||||||
Dialect const& m_dialect;
|
Dialect const& m_dialect;
|
||||||
/// Values of variables.
|
/// Values of variables.
|
||||||
@ -209,6 +219,8 @@ private:
|
|||||||
Scope& m_scope;
|
Scope& m_scope;
|
||||||
/// Current value of the expression
|
/// Current value of the expression
|
||||||
std::vector<u256> m_values;
|
std::vector<u256> m_values;
|
||||||
|
/// Current expression nesting level
|
||||||
|
unsigned m_nestingLevel = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user