mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Move direct struct recursion check to detect recursion in global structs.
This commit is contained in:
parent
b744a56801
commit
6f06154eb5
@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
|
|
||||||
|
#include <libsolutil/Algorithms.h>
|
||||||
|
|
||||||
#include <boost/range/adaptor/transformed.hpp>
|
#include <boost/range/adaptor/transformed.hpp>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -79,10 +81,12 @@ bool DeclarationTypeChecker::visit(StructDefinition const& _struct)
|
|||||||
|
|
||||||
m_currentStructsSeen.insert(&_struct);
|
m_currentStructsSeen.insert(&_struct);
|
||||||
|
|
||||||
for (auto const& _member: _struct.members())
|
for (auto const& member: _struct.members())
|
||||||
{
|
{
|
||||||
m_recursiveStructSeen = false;
|
m_recursiveStructSeen = false;
|
||||||
_member->accept(*this);
|
member->accept(*this);
|
||||||
|
solAssert(member->annotation().type, "");
|
||||||
|
solAssert(member->annotation().type->canBeStored(), "Type cannot be used in struct.");
|
||||||
if (m_recursiveStructSeen)
|
if (m_recursiveStructSeen)
|
||||||
hasRecursiveChild = true;
|
hasRecursiveChild = true;
|
||||||
}
|
}
|
||||||
@ -94,6 +98,29 @@ bool DeclarationTypeChecker::visit(StructDefinition const& _struct)
|
|||||||
if (m_currentStructsSeen.empty())
|
if (m_currentStructsSeen.empty())
|
||||||
m_recursiveStructSeen = false;
|
m_recursiveStructSeen = false;
|
||||||
|
|
||||||
|
// Check direct recursion, fatal error if detected.
|
||||||
|
auto visitor = [&](StructDefinition const& _struct, auto& _cycleDetector, size_t _depth)
|
||||||
|
{
|
||||||
|
if (_depth >= 256)
|
||||||
|
fatalDeclarationError(_struct.location(), "Struct definition exhausting cyclic dependency validator.");
|
||||||
|
|
||||||
|
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
||||||
|
{
|
||||||
|
Type const* memberType = member->annotation().type;
|
||||||
|
while (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
||||||
|
{
|
||||||
|
if (arrayType->isDynamicallySized())
|
||||||
|
break;
|
||||||
|
memberType = arrayType->baseType();
|
||||||
|
}
|
||||||
|
if (auto structType = dynamic_cast<StructType const*>(memberType))
|
||||||
|
if (_cycleDetector.run(structType->structDefinition()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (util::CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr)
|
||||||
|
fatalTypeError(_struct.location(), "Recursive struct definition.");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,6 +369,12 @@ void DeclarationTypeChecker::fatalTypeError(SourceLocation const& _location, str
|
|||||||
m_errorReporter.fatalTypeError(_location, _description);
|
m_errorReporter.fatalTypeError(_location, _description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeclarationTypeChecker::fatalDeclarationError(SourceLocation const& _location, string const& _description)
|
||||||
|
{
|
||||||
|
m_errorOccurred = true;
|
||||||
|
m_errorReporter.fatalDeclarationError(_location, _description);
|
||||||
|
}
|
||||||
|
|
||||||
bool DeclarationTypeChecker::check(ASTNode const& _node)
|
bool DeclarationTypeChecker::check(ASTNode const& _node)
|
||||||
{
|
{
|
||||||
_node.accept(*this);
|
_node.accept(*this);
|
||||||
|
@ -65,6 +65,9 @@ private:
|
|||||||
/// Adds a new error to the list of errors and throws to abort reference resolving.
|
/// Adds a new error to the list of errors and throws to abort reference resolving.
|
||||||
void fatalTypeError(langutil::SourceLocation const& _location, std::string const& _description);
|
void fatalTypeError(langutil::SourceLocation const& _location, std::string const& _description);
|
||||||
|
|
||||||
|
/// Adds a new error to the list of errors and throws to abort reference resolving.
|
||||||
|
void fatalDeclarationError(langutil::SourceLocation const& _location, std::string const& _description);
|
||||||
|
|
||||||
langutil::ErrorReporter& m_errorReporter;
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
bool m_errorOccurred = false;
|
bool m_errorOccurred = false;
|
||||||
langutil::EVMVersion m_evmVersion;
|
langutil::EVMVersion m_evmVersion;
|
||||||
|
@ -289,39 +289,6 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
|||||||
m_errorReporter.fatalTypeError(_usingFor.libraryName().location(), "Library name expected.");
|
m_errorReporter.fatalTypeError(_usingFor.libraryName().location(), "Library name expected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeChecker::visit(StructDefinition const& _struct)
|
|
||||||
{
|
|
||||||
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
|
||||||
solAssert(type(*member)->canBeStored(), "Type cannot be used in struct.");
|
|
||||||
|
|
||||||
// Check recursion, fatal error if detected.
|
|
||||||
auto visitor = [&](StructDefinition const& _struct, CycleDetector<StructDefinition>& _cycleDetector, size_t _depth)
|
|
||||||
{
|
|
||||||
if (_depth >= 256)
|
|
||||||
m_errorReporter.fatalDeclarationError(_struct.location(), "Struct definition exhausting cyclic dependency validator.");
|
|
||||||
|
|
||||||
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
|
||||||
{
|
|
||||||
Type const* memberType = type(*member);
|
|
||||||
while (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
|
||||||
{
|
|
||||||
if (arrayType->isDynamicallySized())
|
|
||||||
break;
|
|
||||||
memberType = arrayType->baseType();
|
|
||||||
}
|
|
||||||
if (auto structType = dynamic_cast<StructType const*>(memberType))
|
|
||||||
if (_cycleDetector.run(structType->structDefinition()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr)
|
|
||||||
m_errorReporter.fatalTypeError(_struct.location(), "Recursive struct definition.");
|
|
||||||
|
|
||||||
ASTNode::listAccept(_struct.members(), *this);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TypeChecker::visit(FunctionDefinition const& _function)
|
bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||||
{
|
{
|
||||||
bool isLibraryFunction = _function.inContractKind() == ContractKind::Library;
|
bool isLibraryFunction = _function.inContractKind() == ContractKind::Library;
|
||||||
|
@ -112,7 +112,6 @@ private:
|
|||||||
|
|
||||||
void endVisit(InheritanceSpecifier const& _inheritance) override;
|
void endVisit(InheritanceSpecifier const& _inheritance) override;
|
||||||
void endVisit(UsingForDirective const& _usingFor) override;
|
void endVisit(UsingForDirective const& _usingFor) override;
|
||||||
bool visit(StructDefinition const& _struct) override;
|
|
||||||
bool visit(FunctionDefinition const& _function) override;
|
bool visit(FunctionDefinition const& _function) override;
|
||||||
bool visit(VariableDeclaration const& _variable) override;
|
bool visit(VariableDeclaration const& _variable) override;
|
||||||
/// We need to do this manually because we want to pass the bases of the current contract in
|
/// We need to do this manually because we want to pass the bases of the current contract in
|
||||||
|
@ -4,7 +4,7 @@ contract C {
|
|||||||
function f(Data.S memory a) public {}
|
function f(Data.S memory a) public {}
|
||||||
}
|
}
|
||||||
contract Data {
|
contract Data {
|
||||||
struct S { S x; }
|
struct S { S[] x; }
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError: (63-78): Recursive type not allowed for public or external contract functions.
|
// TypeError: (63-78): Recursive type not allowed for public or external contract functions.
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
var x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// ParserError: (27-30): Expected explicit type name.
|
@ -0,0 +1,8 @@
|
|||||||
|
struct s1 { s2 x; }
|
||||||
|
struct s2 { s1 y; }
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
// whatever
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError: (0-19): Recursive struct definition.
|
Loading…
Reference in New Issue
Block a user