mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Clear all mapping knowledge after array variable assignment
This commit is contained in:
		
							parent
							
								
									6a2809a582
								
							
						
					
					
						commit
						9199718ec0
					
				| @ -93,9 +93,10 @@ bool SMTChecker::visit(FunctionDefinition const& _function) | ||||
| 		m_uninterpretedTerms.clear(); | ||||
| 		resetStateVariables(); | ||||
| 		initializeLocalVariables(_function); | ||||
| 		m_loopExecutionHappened = false; | ||||
| 		m_arrayAssignmentHappened = false; | ||||
| 	} | ||||
| 
 | ||||
| 	m_loopExecutionHappened = false; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| @ -272,7 +273,7 @@ void SMTChecker::endVisit(Assignment const& _assignment) | ||||
| 	} | ||||
| 	else if (dynamic_cast<IndexAccess const*>(&_assignment.leftHandSide())) | ||||
| 	{ | ||||
| 		arrayAssignment(_assignment); | ||||
| 		arrayIndexAssignment(_assignment); | ||||
| 		defineExpr(_assignment, expr(_assignment.rightHandSide())); | ||||
| 	} | ||||
| 	else | ||||
| @ -463,6 +464,13 @@ void SMTChecker::visitGasLeft(FunctionCall const& _funCall) | ||||
| 		m_interface->addAssertion(symbolicVar->currentValue() <= symbolicVar->valueAtIndex(index - 1)); | ||||
| } | ||||
| 
 | ||||
| void SMTChecker::eraseArrayKnowledge() | ||||
| { | ||||
| 	for (auto const& var: m_variables) | ||||
| 		if (var.first->annotation().type->category() == Type::Category::Mapping) | ||||
| 			newValue(*var.first); | ||||
| } | ||||
| 
 | ||||
| void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall) | ||||
| { | ||||
| 	FunctionDefinition const* _funDef = nullptr; | ||||
| @ -678,7 +686,13 @@ void SMTChecker::endVisit(IndexAccess const& _indexAccess) | ||||
| 	m_uninterpretedTerms.insert(&_indexAccess); | ||||
| } | ||||
| 
 | ||||
| void SMTChecker::arrayAssignment(Assignment const& _assignment) | ||||
| void SMTChecker::arrayAssignment() | ||||
| { | ||||
| 	m_arrayAssignmentHappened = true; | ||||
| 	eraseArrayKnowledge(); | ||||
| } | ||||
| 
 | ||||
| void SMTChecker::arrayIndexAssignment(Assignment const& _assignment) | ||||
| { | ||||
| 	auto const& indexAccess = dynamic_cast<IndexAccess const&>(_assignment.leftHandSide()); | ||||
| 	if (auto const& id = dynamic_cast<Identifier const*>(&indexAccess.baseExpression())) | ||||
| @ -869,6 +883,8 @@ void SMTChecker::assignment(VariableDeclaration const& _variable, smt::Expressio | ||||
| 		checkUnderOverflow(_value, *intType, _location); | ||||
| 	else if (dynamic_cast<AddressType const*>(type.get())) | ||||
| 		checkUnderOverflow(_value, IntegerType(160), _location); | ||||
| 	else if (dynamic_cast<MappingType const*>(type.get())) | ||||
| 		arrayAssignment(); | ||||
| 	m_interface->addAssertion(newValue(_variable) == _value); | ||||
| } | ||||
| 
 | ||||
| @ -949,6 +965,12 @@ void SMTChecker::checkCondition( | ||||
| 		loopComment = | ||||
| 			"\nNote that some information is erased after the execution of loops.\n" | ||||
| 			"You can re-introduce information using require()."; | ||||
| 	if (m_arrayAssignmentHappened) | ||||
| 		loopComment += | ||||
| 			"\nNote that array aliasing is not supported," | ||||
| 			" therefore all mapping information is erased after" | ||||
| 			" a mapping local variable/parameter is assigned.\n" | ||||
| 			"You can re-introduce information using require()."; | ||||
| 
 | ||||
| 	switch (result) | ||||
| 	{ | ||||
| @ -1082,7 +1104,11 @@ void SMTChecker::initializeFunctionCallParameters(FunctionDefinition const& _fun | ||||
| 	solAssert(funParams.size() == _callArgs.size(), ""); | ||||
| 	for (unsigned i = 0; i < funParams.size(); ++i) | ||||
| 		if (createVariable(*funParams[i])) | ||||
| 		{ | ||||
| 			m_interface->addAssertion(_callArgs[i] == newValue(*funParams[i])); | ||||
| 			if (funParams[i]->annotation().type->category() == Type::Category::Mapping) | ||||
| 				m_arrayAssignmentHappened = true; | ||||
| 		} | ||||
| 
 | ||||
| 	for (auto const& variable: _function.localVariables()) | ||||
| 		if (createVariable(*variable)) | ||||
|  | ||||
| @ -97,7 +97,14 @@ private: | ||||
| 
 | ||||
| 	void defineGlobalVariable(std::string const& _name, Expression const& _expr, bool _increaseIndex = false); | ||||
| 	void defineGlobalFunction(std::string const& _name, Expression const& _expr); | ||||
| 	void arrayAssignment(Assignment const& _assignment); | ||||
| 	/// Handles the side effects of assignment
 | ||||
| 	/// to variable of some SMT array type
 | ||||
| 	/// while aliasing is not supported.
 | ||||
| 	void arrayAssignment(); | ||||
| 	/// Handles assignment to SMT array index.
 | ||||
| 	void arrayIndexAssignment(Assignment const& _assignment); | ||||
| 	/// Erases information about SMT arrays.
 | ||||
| 	void eraseArrayKnowledge(); | ||||
| 
 | ||||
| 	/// Division expression in the given type. Requires special treatment because
 | ||||
| 	/// of rounding for signed division.
 | ||||
| @ -205,6 +212,7 @@ private: | ||||
| 	std::shared_ptr<smt::SolverInterface> m_interface; | ||||
| 	std::shared_ptr<VariableUsage> m_variableUsage; | ||||
| 	bool m_loopExecutionHappened = false; | ||||
| 	bool m_arrayAssignmentHappened = false; | ||||
| 	/// An Expression may have multiple smt::Expression due to
 | ||||
| 	/// repeated calls to the same function.
 | ||||
| 	std::unordered_map<Expression const*, std::shared_ptr<SymbolicVariable>> m_expressions; | ||||
|  | ||||
| @ -7,9 +7,12 @@ contract C | ||||
| 
 | ||||
| 	function f() public { | ||||
| 		require(a[1] == b[1]); | ||||
| 		a[1] = 2; | ||||
| 		mapping (uint => uint) storage c = a; | ||||
| 		c[1] = 2; | ||||
| 		assert(c[1] == 2); | ||||
| 		// False negative! Needs aliasing. | ||||
| 		assert(a[1] == b[1]); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (261-281): Assertion violation happens here | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user