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,9 +2463,16 @@ 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) {
[&](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.
@ -2482,22 +2489,19 @@ TypeResult StructType::interfaceType(bool _inLibrary) const
Type const* memberType = variable->annotation().type;
while (dynamic_cast<ArrayType const*>(memberType))
memberType = dynamic_cast<ArrayType const*>(memberType)->baseType();
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))
{
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);

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 {}
}