mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #9159 from ethereum/smt_nondet_mod
[SMTChecker] Replace explicit mod by slack variables
This commit is contained in:
		
						commit
						633b170f58
					
				| @ -32,12 +32,23 @@ EncodingContext::EncodingContext(): | ||||
| void EncodingContext::reset() | ||||
| { | ||||
| 	resetAllVariables(); | ||||
| 	resetSlackId(); | ||||
| 	m_expressions.clear(); | ||||
| 	m_globalContext.clear(); | ||||
| 	m_state.reset(); | ||||
| 	m_assertions.clear(); | ||||
| } | ||||
| 
 | ||||
| void EncodingContext::resetSlackId() | ||||
| { | ||||
| 	m_nextSlackId = 0; | ||||
| } | ||||
| 
 | ||||
| unsigned EncodingContext::newSlackId() | ||||
| { | ||||
| 	return m_nextSlackId++; | ||||
| } | ||||
| 
 | ||||
| void EncodingContext::clear() | ||||
| { | ||||
| 	m_variables.clear(); | ||||
|  | ||||
| @ -40,6 +40,10 @@ public: | ||||
| 	/// alive because of state variables and inlined function calls.
 | ||||
| 	/// To be used in the beginning of a root function visit.
 | ||||
| 	void reset(); | ||||
| 	/// Resets the fresh id for slack variables.
 | ||||
| 	void resetSlackId(); | ||||
| 	/// Returns the current fresh slack id and increments it.
 | ||||
| 	unsigned newSlackId(); | ||||
| 	/// Clears the entire context, erasing everything.
 | ||||
| 	/// To be used before a model checking engine starts.
 | ||||
| 	void clear(); | ||||
| @ -168,6 +172,9 @@ private: | ||||
| 	/// Whether to conjoin assertions in the assertion stack.
 | ||||
| 	bool m_accumulateAssertions = true; | ||||
| 	//@}
 | ||||
| 
 | ||||
| 	/// Fresh ids for slack variables to be created deterministically.
 | ||||
| 	unsigned m_nextSlackId = 0; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -1204,7 +1204,7 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation( | ||||
| 	smtutil::Expression const& _left, | ||||
| 	smtutil::Expression const& _right, | ||||
| 	TypePointer const& _commonType, | ||||
| 	Expression const& | ||||
| 	Expression const& _operation | ||||
| ) | ||||
| { | ||||
| 	static set<Token> validOperators{ | ||||
| @ -1227,39 +1227,66 @@ pair<smtutil::Expression, smtutil::Expression> SMTEncoder::arithmeticOperation( | ||||
| 	else | ||||
| 		intType = TypeProvider::uint256(); | ||||
| 
 | ||||
| 	smtutil::Expression valueNoMod( | ||||
| 		_op == Token::Add ? _left + _right : | ||||
| 		_op == Token::Sub ? _left - _right : | ||||
| 		_op == Token::Div ? division(_left, _right, *intType) : | ||||
| 		_op == Token::Mul ? _left * _right : | ||||
| 		/*_op == Token::Mod*/ _left % _right | ||||
| 	); | ||||
| 	auto valueUnbounded = [&]() -> smtutil::Expression { | ||||
| 		switch (_op) | ||||
| 		{ | ||||
| 		case Token::Add: return _left + _right; | ||||
| 		case Token::Sub: return _left - _right; | ||||
| 		case Token::Mul: return _left * _right; | ||||
| 		case Token::Div: return division(_left, _right, *intType); | ||||
| 		case Token::Mod: return _left % _right; | ||||
| 		default: solAssert(false, ""); | ||||
| 		} | ||||
| 	}(); | ||||
| 
 | ||||
| 	if (_op == Token::Div || _op == Token::Mod) | ||||
| 	{ | ||||
| 		m_context.addAssertion(_right != 0); | ||||
| 
 | ||||
| 		// mod and unsigned division never underflow/overflow
 | ||||
| 		if (_op == Token::Mod || !intType->isSigned()) | ||||
| 			return {valueUnbounded, valueUnbounded}; | ||||
| 
 | ||||
| 		// The only case where division overflows is
 | ||||
| 		// - type is signed
 | ||||
| 		// - LHS is type.min
 | ||||
| 		// - RHS is -1
 | ||||
| 		// the result is then -(type.min), which wraps back to type.min
 | ||||
| 		smtutil::Expression maxLeft = _left == smt::minValue(*intType); | ||||
| 		smtutil::Expression minusOneRight = _right == -1; | ||||
| 		smtutil::Expression wrap = smtutil::Expression::ite(maxLeft && minusOneRight, smt::minValue(*intType), valueUnbounded); | ||||
| 		return {wrap, valueUnbounded}; | ||||
| 	} | ||||
| 
 | ||||
| 	auto symbMin = smt::minValue(*intType); | ||||
| 	auto symbMax = smt::maxValue(*intType); | ||||
| 
 | ||||
| 	smtutil::Expression intValueRange = (0 - symbMin) + symbMax + 1; | ||||
| 	string suffix = to_string(_operation.id()) + "_" + to_string(m_context.newSlackId()); | ||||
| 	smt::SymbolicIntVariable k(intType, intType, "k_" + suffix, m_context); | ||||
| 	smt::SymbolicIntVariable m(intType, intType, "m_" + suffix, m_context); | ||||
| 
 | ||||
| 	// To wrap around valueUnbounded in case of overflow or underflow, we replace it with a k, given:
 | ||||
| 	// 1. k + m * intValueRange = valueUnbounded
 | ||||
| 	// 2. k is in range of the desired integer type
 | ||||
| 	auto wrap = k.currentValue(); | ||||
| 	m_context.addAssertion(valueUnbounded == (k.currentValue() + intValueRange * m.currentValue())); | ||||
| 	m_context.addAssertion(k.currentValue() >= symbMin); | ||||
| 	m_context.addAssertion(k.currentValue() <= symbMax); | ||||
| 
 | ||||
| 	// TODO this could be refined:
 | ||||
| 	// for unsigned types it's enough to check only the upper bound.
 | ||||
| 	auto value = smtutil::Expression::ite( | ||||
| 		valueNoMod > symbMax, | ||||
| 		valueNoMod % intValueRange, | ||||
| 		valueUnbounded > symbMax, | ||||
| 		wrap, | ||||
| 		smtutil::Expression::ite( | ||||
| 			valueNoMod < symbMin, | ||||
| 			valueNoMod % intValueRange, | ||||
| 			valueNoMod | ||||
| 			valueUnbounded < symbMin, | ||||
| 			wrap, | ||||
| 			valueUnbounded | ||||
| 		) | ||||
| 	); | ||||
| 
 | ||||
| 	if (intType->isSigned()) | ||||
| 		value = smtutil::Expression::ite( | ||||
| 			value > symbMax, | ||||
| 			value - intValueRange, | ||||
| 			value | ||||
| 		); | ||||
| 
 | ||||
| 	return {value, valueNoMod}; | ||||
| 	return {value, valueUnbounded}; | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::compareOperation(BinaryOperation const& _op) | ||||
|  | ||||
| @ -22,4 +22,3 @@ contract C | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (130-144): Error trying to invoke SMT solver. | ||||
|  | ||||
| @ -14,6 +14,4 @@ contract C | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (296-309): Error trying to invoke SMT solver. | ||||
| // Warning: (176-181): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (296-309): Assertion violation happens here | ||||
|  | ||||
| @ -19,7 +19,5 @@ contract LoopFor2 { | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (317-337): Error trying to invoke SMT solver. | ||||
| // Warning: (317-337): Assertion violation happens here | ||||
| // Warning: (341-360): Assertion violation happens here | ||||
| // Warning: (364-383): Assertion violation happens here | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user