Merge pull request #9686 from ethereum/fix-infinite-loop

Fix infinite loop
This commit is contained in:
chriseth 2020-08-27 15:55:08 +02:00 committed by GitHub
commit e5b9a33998
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 39 deletions

View File

@ -22,6 +22,7 @@ Bugfixes:
* Yul Optimizer: Make function inlining order more resilient to whether or not unrelated source files are present.
* Type Checker: Disallow signed literals as exponent in exponentiation operator.
* Allow `type(Contract).name` for abstract contracts and interfaces.
* Type Checker: Disallow structs containing nested mapping in memory as parameters for library functions.
### 0.7.0 (2020-07-28)

View File

@ -2463,52 +2463,56 @@ TypeResult StructType::interfaceType(bool _inLibrary) const
TypeResult result{TypePointer{}};
if (recursive() && !(_inLibrary && location() == DataLocation::Storage))
return TypeResult::err(
"Recursive structs can only be passed as storage pointers to libraries, "
"not as memory objects to contract functions."
);
util::BreadthFirstSearch<StructDefinition const*> breadthFirstSearch{{&m_struct}};
breadthFirstSearch.run(
[&](StructDefinition const* _struct, auto&& _addChild) {
// Check that all members have interface types.
// Return an error if at least one struct member does not have a type.
// This might happen, for example, if the type of the member does not exist.
for (ASTPointer<VariableDeclaration> const& variable: _struct->members())
[&](StructDefinition const* _struct, auto&& _addChild)
{
// Check that all members have interface types.
// Return an error if at least one struct member does not have a type.
// This might happen, for example, if the type of the member does not exist.
for (ASTPointer<VariableDeclaration> const& variable: _struct->members())
{
// If the struct member does not have a type return false.
// A TypeError is expected in this case.
if (!variable->annotation().type)
{
// If the struct member does not have a type return false.
// A TypeError is expected in this case.
if (!variable->annotation().type)
result = TypeResult::err("Invalid type!");
breadthFirstSearch.abort();
return;
}
Type const* memberType = variable->annotation().type;
while (
memberType->category() == Type::Category::Array ||
memberType->category() == Type::Category::Mapping
)
{
if (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
memberType = arrayType->finalBaseType(false);
else if (auto mappingType = dynamic_cast<MappingType const*>(memberType))
memberType = mappingType->valueType();
}
if (StructType const* innerStruct = dynamic_cast<StructType const*>(memberType))
_addChild(&innerStruct->structDefinition());
else
{
auto iType = memberType->interfaceType(_inLibrary);
if (!iType.get())
{
result = TypeResult::err("Invalid type!");
solAssert(!iType.message().empty(), "Expected detailed error message!");
result = iType;
breadthFirstSearch.abort();
return;
}
Type const* memberType = variable->annotation().type;
while (dynamic_cast<ArrayType const*>(memberType))
memberType = dynamic_cast<ArrayType const*>(memberType)->baseType();
if (StructType const* innerStruct = dynamic_cast<StructType const*>(memberType))
{
if (innerStruct->recursive() && !(_inLibrary && location() == DataLocation::Storage))
{
result = TypeResult::err(
"Recursive structs can only be passed as storage pointers to libraries, not as memory objects to contract functions."
);
breadthFirstSearch.abort();
return;
}
else
_addChild(&innerStruct->structDefinition());
}
else
{
auto iType = memberType->interfaceType(_inLibrary);
if (!iType.get())
{
solAssert(!iType.message().empty(), "Expected detailed error message!");
result = iType;
breadthFirstSearch.abort();
return;
}
}
}
}
}
);

View File

@ -0,0 +1,10 @@
library a {
struct b {
mapping (uint => b) c ;
}
// Segfaults in https://github.com/ethereum/solidity/issues/9443
function d(b memory) public {}
}
// ----
// TypeError 4103: (149-157): Recursive structs can only be passed as storage pointers to libraries, not as memory objects to contract functions.
// TypeError 4061: (149-157): Type struct a.b is only valid in storage because it contains a (nested) mapping.

View File

@ -0,0 +1,6 @@
library a {
struct b {
mapping (uint => b) c ;
}
function d(b storage) public {}
}