mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9686 from ethereum/fix-infinite-loop
Fix infinite loop
This commit is contained in:
commit
e5b9a33998
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -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.
|
@ -0,0 +1,6 @@
|
||||
library a {
|
||||
struct b {
|
||||
mapping (uint => b) c ;
|
||||
}
|
||||
function d(b storage) public {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user