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:
|
Bugfixes:
|
||||||
* Assembly Parser: Be more strict about number literals.
|
* Assembly Parser: Be more strict about number literals.
|
||||||
|
* Assembly Parser: Limit maximum recursion depth.
|
||||||
* Parser: Enforce commas between array and tuple elements.
|
* Parser: Enforce commas between array and tuple elements.
|
||||||
* Parser: Limit maximum recursion depth.
|
* Parser: Limit maximum recursion depth.
|
||||||
* Type Checker: Crash fix related to ``using``.
|
* 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)
|
shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner)
|
||||||
{
|
{
|
||||||
|
m_recursionDepth = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_scanner = _scanner;
|
m_scanner = _scanner;
|
||||||
@ -51,6 +52,7 @@ shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scann
|
|||||||
|
|
||||||
assembly::Block Parser::parseBlock()
|
assembly::Block Parser::parseBlock()
|
||||||
{
|
{
|
||||||
|
RecursionGuard recursionGuard(*this);
|
||||||
assembly::Block block = createWithLocation<Block>();
|
assembly::Block block = createWithLocation<Block>();
|
||||||
expectToken(Token::LBrace);
|
expectToken(Token::LBrace);
|
||||||
while (currentToken() != Token::RBrace)
|
while (currentToken() != Token::RBrace)
|
||||||
@ -62,6 +64,7 @@ assembly::Block Parser::parseBlock()
|
|||||||
|
|
||||||
assembly::Statement Parser::parseStatement()
|
assembly::Statement Parser::parseStatement()
|
||||||
{
|
{
|
||||||
|
RecursionGuard recursionGuard(*this);
|
||||||
switch (currentToken())
|
switch (currentToken())
|
||||||
{
|
{
|
||||||
case Token::Let:
|
case Token::Let:
|
||||||
@ -158,6 +161,7 @@ assembly::Statement Parser::parseStatement()
|
|||||||
|
|
||||||
assembly::Case Parser::parseCase()
|
assembly::Case Parser::parseCase()
|
||||||
{
|
{
|
||||||
|
RecursionGuard recursionGuard(*this);
|
||||||
assembly::Case _case = createWithLocation<assembly::Case>();
|
assembly::Case _case = createWithLocation<assembly::Case>();
|
||||||
if (m_scanner->currentToken() == Token::Default)
|
if (m_scanner->currentToken() == Token::Default)
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
@ -178,6 +182,7 @@ assembly::Case Parser::parseCase()
|
|||||||
|
|
||||||
assembly::ForLoop Parser::parseForLoop()
|
assembly::ForLoop Parser::parseForLoop()
|
||||||
{
|
{
|
||||||
|
RecursionGuard recursionGuard(*this);
|
||||||
ForLoop forLoop = createWithLocation<ForLoop>();
|
ForLoop forLoop = createWithLocation<ForLoop>();
|
||||||
expectToken(Token::For);
|
expectToken(Token::For);
|
||||||
forLoop.pre = parseBlock();
|
forLoop.pre = parseBlock();
|
||||||
@ -192,6 +197,7 @@ assembly::ForLoop Parser::parseForLoop()
|
|||||||
|
|
||||||
assembly::Statement Parser::parseExpression()
|
assembly::Statement Parser::parseExpression()
|
||||||
{
|
{
|
||||||
|
RecursionGuard recursionGuard(*this);
|
||||||
Statement operation = parseElementaryOperation(true);
|
Statement operation = parseElementaryOperation(true);
|
||||||
if (operation.type() == typeid(Instruction))
|
if (operation.type() == typeid(Instruction))
|
||||||
{
|
{
|
||||||
@ -254,6 +260,7 @@ std::map<dev::solidity::Instruction, string> const& Parser::instructionNames()
|
|||||||
|
|
||||||
assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
|
assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
|
||||||
{
|
{
|
||||||
|
RecursionGuard recursionGuard(*this);
|
||||||
Statement ret;
|
Statement ret;
|
||||||
switch (currentToken())
|
switch (currentToken())
|
||||||
{
|
{
|
||||||
@ -342,6 +349,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
|
|||||||
|
|
||||||
assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
||||||
{
|
{
|
||||||
|
RecursionGuard recursionGuard(*this);
|
||||||
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
|
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
|
||||||
expectToken(Token::Let);
|
expectToken(Token::Let);
|
||||||
while (true)
|
while (true)
|
||||||
@ -366,6 +374,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
|||||||
|
|
||||||
assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
||||||
{
|
{
|
||||||
|
RecursionGuard recursionGuard(*this);
|
||||||
FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
|
FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
|
||||||
expectToken(Token::Function);
|
expectToken(Token::Function);
|
||||||
funDef.name = expectAsmIdentifier();
|
funDef.name = expectAsmIdentifier();
|
||||||
@ -397,6 +406,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
|
|||||||
|
|
||||||
assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
|
assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
|
||||||
{
|
{
|
||||||
|
RecursionGuard recursionGuard(*this);
|
||||||
if (_instruction.type() == typeid(Instruction))
|
if (_instruction.type() == typeid(Instruction))
|
||||||
{
|
{
|
||||||
solAssert(!m_julia, "Instructions are invalid in JULIA");
|
solAssert(!m_julia, "Instructions are invalid in JULIA");
|
||||||
@ -479,6 +489,7 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
|
|||||||
|
|
||||||
TypedName Parser::parseTypedName()
|
TypedName Parser::parseTypedName()
|
||||||
{
|
{
|
||||||
|
RecursionGuard recursionGuard(*this);
|
||||||
TypedName typedName = createWithLocation<TypedName>();
|
TypedName typedName = createWithLocation<TypedName>();
|
||||||
typedName.name = expectAsmIdentifier();
|
typedName.name = expectAsmIdentifier();
|
||||||
if (m_julia)
|
if (m_julia)
|
||||||
|
@ -64,25 +64,6 @@ private:
|
|||||||
SourceLocation m_location;
|
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)
|
ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -1543,19 +1524,6 @@ ASTPointer<ParameterList> Parser::createEmptyParameterList()
|
|||||||
return nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>());
|
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()
|
string Parser::currentTokenName()
|
||||||
{
|
{
|
||||||
Token::Value token = m_scanner->currentToken();
|
Token::Value token = m_scanner->currentToken();
|
||||||
|
@ -41,7 +41,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
class ASTNodeFactory;
|
class ASTNodeFactory;
|
||||||
class RecursionGuard;
|
|
||||||
|
|
||||||
struct VarDeclParserOptions
|
struct VarDeclParserOptions
|
||||||
{
|
{
|
||||||
@ -165,14 +164,8 @@ private:
|
|||||||
/// Creates an empty ParameterList at the current location (used if parameters can be omitted).
|
/// Creates an empty ParameterList at the current location (used if parameters can be omitted).
|
||||||
ASTPointer<ParameterList> createEmptyParameterList();
|
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.
|
/// Flag that signifies whether '_' is parsed as a PlaceholderStatement or a regular identifier.
|
||||||
bool m_insideModifier = false;
|
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();
|
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)
|
void ParserBase::parserError(string const& _description)
|
||||||
{
|
{
|
||||||
m_errorReporter.parserError(SourceLocation(position(), position(), sourceName()), _description);
|
m_errorReporter.parserError(SourceLocation(position(), position(), sourceName()), _description);
|
||||||
|
@ -41,6 +41,20 @@ public:
|
|||||||
std::shared_ptr<std::string const> const& sourceName() const;
|
std::shared_ptr<std::string const> const& sourceName() const;
|
||||||
|
|
||||||
protected:
|
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
|
/// Start position of the current token
|
||||||
int position() const;
|
int position() const;
|
||||||
/// End position of the current token
|
/// End position of the current token
|
||||||
@ -56,6 +70,10 @@ protected:
|
|||||||
Token::Value advance();
|
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
|
/// Creates a @ref ParserError and annotates it with the current position and the
|
||||||
/// given @a _description.
|
/// given @a _description.
|
||||||
void parserError(std::string const& _description);
|
void parserError(std::string const& _description);
|
||||||
@ -67,6 +85,8 @@ protected:
|
|||||||
std::shared_ptr<Scanner> m_scanner;
|
std::shared_ptr<Scanner> m_scanner;
|
||||||
/// The reference to the list of errors and warning to add errors/warnings during parsing
|
/// The reference to the list of errors and warning to add errors/warnings during parsing
|
||||||
ErrorReporter& m_errorReporter;
|
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_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()
|
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)");
|
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_END()
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(Printing)
|
BOOST_AUTO_TEST_SUITE(Printing)
|
||||||
|
Loading…
Reference in New Issue
Block a user