mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2770 from ethereum/recursionInAsm
Also prevent too much recursion in the assembly parser.
This commit is contained in:
commit
8af6f193bc
@ -13,6 +13,7 @@ Features:
|
||||
|
||||
Bugfixes:
|
||||
* Assembly Parser: Be more strict about number literals.
|
||||
* Assembly Parser: Limit maximum recursion depth.
|
||||
* Parser: Enforce commas between array and tuple elements.
|
||||
* Parser: Limit maximum recursion depth.
|
||||
* Type Checker: Crash fix related to ``using``.
|
||||
|
@ -36,6 +36,7 @@ using namespace dev::solidity::assembly;
|
||||
|
||||
shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner)
|
||||
{
|
||||
m_recursionDepth = 0;
|
||||
try
|
||||
{
|
||||
m_scanner = _scanner;
|
||||
@ -51,6 +52,7 @@ shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scann
|
||||
|
||||
assembly::Block Parser::parseBlock()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
assembly::Block block = createWithLocation<Block>();
|
||||
expectToken(Token::LBrace);
|
||||
while (currentToken() != Token::RBrace)
|
||||
@ -62,6 +64,7 @@ assembly::Block Parser::parseBlock()
|
||||
|
||||
assembly::Statement Parser::parseStatement()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
switch (currentToken())
|
||||
{
|
||||
case Token::Let:
|
||||
@ -158,6 +161,7 @@ assembly::Statement Parser::parseStatement()
|
||||
|
||||
assembly::Case Parser::parseCase()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
assembly::Case _case = createWithLocation<assembly::Case>();
|
||||
if (m_scanner->currentToken() == Token::Default)
|
||||
m_scanner->next();
|
||||
@ -178,6 +182,7 @@ assembly::Case Parser::parseCase()
|
||||
|
||||
assembly::ForLoop Parser::parseForLoop()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
ForLoop forLoop = createWithLocation<ForLoop>();
|
||||
expectToken(Token::For);
|
||||
forLoop.pre = parseBlock();
|
||||
@ -192,6 +197,7 @@ assembly::ForLoop Parser::parseForLoop()
|
||||
|
||||
assembly::Statement Parser::parseExpression()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
Statement operation = parseElementaryOperation(true);
|
||||
if (operation.type() == typeid(Instruction))
|
||||
{
|
||||
@ -254,6 +260,7 @@ std::map<dev::solidity::Instruction, string> const& Parser::instructionNames()
|
||||
|
||||
assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
Statement ret;
|
||||
switch (currentToken())
|
||||
{
|
||||
@ -342,6 +349,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
|
||||
|
||||
assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
|
||||
expectToken(Token::Let);
|
||||
while (true)
|
||||
@ -366,6 +374,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
||||
|
||||
assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
|
||||
expectToken(Token::Function);
|
||||
funDef.name = expectAsmIdentifier();
|
||||
@ -397,6 +406,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
||||
|
||||
assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
if (_instruction.type() == typeid(Instruction))
|
||||
{
|
||||
solAssert(!m_julia, "Instructions are invalid in JULIA");
|
||||
@ -479,6 +489,7 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
|
||||
|
||||
TypedName Parser::parseTypedName()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
TypedName typedName = createWithLocation<TypedName>();
|
||||
typedName.name = expectAsmIdentifier();
|
||||
if (m_julia)
|
||||
|
@ -64,25 +64,6 @@ private:
|
||||
SourceLocation m_location;
|
||||
};
|
||||
|
||||
/// Utility class that creates an error and throws an exception if the
|
||||
/// recursion depth is too deep.
|
||||
class Parser::RecursionGuard
|
||||
{
|
||||
public:
|
||||
explicit RecursionGuard(Parser& _parser):
|
||||
m_parser(_parser)
|
||||
{
|
||||
m_parser.increaseRecursionDepth();
|
||||
}
|
||||
~RecursionGuard()
|
||||
{
|
||||
m_parser.decreaseRecursionDepth();
|
||||
}
|
||||
|
||||
private:
|
||||
Parser& m_parser;
|
||||
};
|
||||
|
||||
ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
|
||||
{
|
||||
try
|
||||
@ -1543,19 +1524,6 @@ ASTPointer<ParameterList> Parser::createEmptyParameterList()
|
||||
return nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>());
|
||||
}
|
||||
|
||||
void Parser::increaseRecursionDepth()
|
||||
{
|
||||
m_recursionDepth++;
|
||||
if (m_recursionDepth >= 4096)
|
||||
fatalParserError("Maximum recursion depth reached during parsing.");
|
||||
}
|
||||
|
||||
void Parser::decreaseRecursionDepth()
|
||||
{
|
||||
solAssert(m_recursionDepth > 0, "");
|
||||
m_recursionDepth--;
|
||||
}
|
||||
|
||||
string Parser::currentTokenName()
|
||||
{
|
||||
Token::Value token = m_scanner->currentToken();
|
||||
|
@ -41,7 +41,6 @@ public:
|
||||
|
||||
private:
|
||||
class ASTNodeFactory;
|
||||
class RecursionGuard;
|
||||
|
||||
struct VarDeclParserOptions
|
||||
{
|
||||
@ -165,14 +164,8 @@ private:
|
||||
/// Creates an empty ParameterList at the current location (used if parameters can be omitted).
|
||||
ASTPointer<ParameterList> createEmptyParameterList();
|
||||
|
||||
/// Increases the recursion depth and throws an exception if it is too deep.
|
||||
void increaseRecursionDepth();
|
||||
void decreaseRecursionDepth();
|
||||
|
||||
/// Flag that signifies whether '_' is parsed as a PlaceholderStatement or a regular identifier.
|
||||
bool m_insideModifier = false;
|
||||
/// Current recursion depth during parsing.
|
||||
size_t m_recursionDepth = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -101,6 +101,19 @@ void ParserBase::expectToken(Token::Value _value)
|
||||
m_scanner->next();
|
||||
}
|
||||
|
||||
void ParserBase::increaseRecursionDepth()
|
||||
{
|
||||
m_recursionDepth++;
|
||||
if (m_recursionDepth >= 3000)
|
||||
fatalParserError("Maximum recursion depth reached during parsing.");
|
||||
}
|
||||
|
||||
void ParserBase::decreaseRecursionDepth()
|
||||
{
|
||||
solAssert(m_recursionDepth > 0, "");
|
||||
m_recursionDepth--;
|
||||
}
|
||||
|
||||
void ParserBase::parserError(string const& _description)
|
||||
{
|
||||
m_errorReporter.parserError(SourceLocation(position(), position(), sourceName()), _description);
|
||||
|
@ -41,6 +41,20 @@ public:
|
||||
std::shared_ptr<std::string const> const& sourceName() const;
|
||||
|
||||
protected:
|
||||
/// Utility class that creates an error and throws an exception if the
|
||||
/// recursion depth is too deep.
|
||||
class RecursionGuard
|
||||
{
|
||||
public:
|
||||
explicit RecursionGuard(ParserBase& _parser): m_parser(_parser)
|
||||
{
|
||||
m_parser.increaseRecursionDepth();
|
||||
}
|
||||
~RecursionGuard() { m_parser.decreaseRecursionDepth(); }
|
||||
private:
|
||||
ParserBase& m_parser;
|
||||
};
|
||||
|
||||
/// Start position of the current token
|
||||
int position() const;
|
||||
/// End position of the current token
|
||||
@ -56,6 +70,10 @@ protected:
|
||||
Token::Value advance();
|
||||
///@}
|
||||
|
||||
/// Increases the recursion depth and throws an exception if it is too deep.
|
||||
void increaseRecursionDepth();
|
||||
void decreaseRecursionDepth();
|
||||
|
||||
/// Creates a @ref ParserError and annotates it with the current position and the
|
||||
/// given @a _description.
|
||||
void parserError(std::string const& _description);
|
||||
@ -67,6 +85,8 @@ protected:
|
||||
std::shared_ptr<Scanner> m_scanner;
|
||||
/// The reference to the list of errors and warning to add errors/warnings during parsing
|
||||
ErrorReporter& m_errorReporter;
|
||||
/// Current recursion depth during parsing.
|
||||
size_t m_recursionDepth = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -237,6 +237,18 @@ BOOST_AUTO_TEST_CASE(builtin_types)
|
||||
BOOST_CHECK(successParse("{ let x:s256 := 1:s256 }"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(recursion_depth)
|
||||
{
|
||||
string input;
|
||||
for (size_t i = 0; i < 20000; i++)
|
||||
input += "{";
|
||||
input += "let x:u256 := 0:u256";
|
||||
for (size_t i = 0; i < 20000; i++)
|
||||
input += "}";
|
||||
|
||||
CHECK_ERROR(input, ParserError, "recursion");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -400,6 +400,20 @@ BOOST_AUTO_TEST_CASE(instruction_too_many_arguments)
|
||||
CHECK_PARSE_ERROR("{ mul(1, 2, 3) }", ParserError, "Expected ')' (\"mul\" expects 2 arguments)");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(recursion_depth)
|
||||
{
|
||||
string input;
|
||||
for (size_t i = 0; i < 20000; i++)
|
||||
input += "{";
|
||||
input += "let x := 0";
|
||||
for (size_t i = 0; i < 20000; i++)
|
||||
input += "}";
|
||||
|
||||
CHECK_PARSE_ERROR(input, ParserError, "recursion");
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Printing)
|
||||
|
Loading…
Reference in New Issue
Block a user