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