mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Disallow invoking the same modifier multiple times.
This commit is contained in:
		
							parent
							
								
									b83f77e0e5
								
							
						
					
					
						commit
						5a75581f66
					
				| @ -15,6 +15,7 @@ Features: | ||||
| 
 | ||||
| Bugfixes: | ||||
|  * Type Checker: Fix address literals not being treated as compile-time constants. | ||||
|  * Type Checker: Disallow invoking the same modifier multiple times. | ||||
|  * Type Checker: Make UTF8-validation a bit more sloppy to include more valid sequences. | ||||
|  * Fixed crash concerning non-callable types. | ||||
|  * Unused variable warnings no longer issued for variables used inside inline assembly. | ||||
|  | ||||
| @ -466,13 +466,26 @@ bool TypeChecker::visit(FunctionDefinition const& _function) | ||||
| 
 | ||||
| 		var->accept(*this); | ||||
| 	} | ||||
| 	set<Declaration const*> modifiers; | ||||
| 	for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers()) | ||||
| 	{ | ||||
| 		visitManually( | ||||
| 			*modifier, | ||||
| 			_function.isConstructor() ? | ||||
| 			dynamic_cast<ContractDefinition const&>(*_function.scope()).annotation().linearizedBaseContracts : | ||||
| 			vector<ContractDefinition const*>() | ||||
| 		); | ||||
| 		Declaration const* decl = &dereference(*modifier->name()); | ||||
| 		if (modifiers.count(decl)) | ||||
| 		{ | ||||
| 			if (dynamic_cast<ContractDefinition const*>(decl)) | ||||
| 				m_errorReporter.declarationError(modifier->location(), "Base constructor already provided."); | ||||
| 			else | ||||
| 				m_errorReporter.declarationError(modifier->location(), "Modifier already used for this function."); | ||||
| 		} | ||||
| 		else | ||||
| 			modifiers.insert(decl); | ||||
| 	} | ||||
| 	if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface) | ||||
| 	{ | ||||
| 		if (_function.isImplemented()) | ||||
|  | ||||
| @ -124,6 +124,7 @@ void CompilerContext::addVariable(VariableDeclaration const& _declaration, | ||||
| 								  unsigned _offsetToCurrent) | ||||
| { | ||||
| 	solAssert(m_asm->deposit() >= 0 && unsigned(m_asm->deposit()) >= _offsetToCurrent, ""); | ||||
| 	solAssert(m_localVariables.count(&_declaration) == 0, "Variable already present"); | ||||
| 	m_localVariables[&_declaration] = unsigned(m_asm->deposit()) - _offsetToCurrent; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -879,6 +879,7 @@ void ContractCompiler::appendModifierOrFunctionCode() | ||||
| 	solAssert(m_currentFunction, ""); | ||||
| 	unsigned stackSurplus = 0; | ||||
| 	Block const* codeBlock = nullptr; | ||||
| 	vector<VariableDeclaration const*> addedVariables; | ||||
| 
 | ||||
| 	m_modifierDepth++; | ||||
| 
 | ||||
| @ -902,6 +903,7 @@ void ContractCompiler::appendModifierOrFunctionCode() | ||||
| 			for (unsigned i = 0; i < modifier.parameters().size(); ++i) | ||||
| 			{ | ||||
| 				m_context.addVariable(*modifier.parameters()[i]); | ||||
| 				addedVariables.push_back(modifier.parameters()[i].get()); | ||||
| 				compileExpression( | ||||
| 					*modifierInvocation->arguments()[i], | ||||
| 					modifier.parameters()[i]->annotation().type | ||||
| @ -928,6 +930,8 @@ void ContractCompiler::appendModifierOrFunctionCode() | ||||
| 		m_returnTags.pop_back(); | ||||
| 
 | ||||
| 		CompilerUtils(m_context).popStackSlots(stackSurplus); | ||||
| 		for (auto var: addedVariables) | ||||
| 			m_context.removeVariable(*var); | ||||
| 	} | ||||
| 	m_modifierDepth--; | ||||
| } | ||||
|  | ||||
| @ -1049,6 +1049,28 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables) | ||||
| 	CHECK_SUCCESS(text); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(function_modifier_double_invocation) | ||||
| { | ||||
| 	char const* text = R"( | ||||
| 		contract B { | ||||
| 			function f(uint x) mod(x) mod(2) { } | ||||
| 			modifier mod(uint a) { if (a > 0) _; } | ||||
| 		} | ||||
| 	)"; | ||||
| 	CHECK_ERROR(text, DeclarationError, "Modifier already used for this function"); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(base_constructor_double_invocation) | ||||
| { | ||||
| 	char const* text = R"( | ||||
| 		contract C { function C(uint a) {} } | ||||
| 		contract B is C { | ||||
| 			function B() C(2) C(2) {} | ||||
| 		} | ||||
| 	)"; | ||||
| 	CHECK_ERROR(text, DeclarationError, "Base constructor already provided"); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(legal_modifier_override) | ||||
| { | ||||
| 	char const* text = R"( | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user