mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #10073 from ethereum/smt_format_array_cex
Format array cex
This commit is contained in:
		
						commit
						1f50b86aad
					
				| @ -211,11 +211,8 @@ private: | |||||||
| 		for (unsigned i = 0; i < _values.size(); ++i) | 		for (unsigned i = 0; i < _values.size(); ++i) | ||||||
| 		{ | 		{ | ||||||
| 			auto var = _variables.at(i); | 			auto var = _variables.at(i); | ||||||
| 			if (var && var->type()->isValueType()) | 			if (var && _values.at(i)) | ||||||
| 			{ |  | ||||||
| 				solAssert(_values.at(i), ""); |  | ||||||
| 				assignments.emplace_back(var->name() + " = " + *_values.at(i)); | 				assignments.emplace_back(var->name() + " = " + *_values.at(i)); | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		return boost::algorithm::join(assignments, _separator); | 		return boost::algorithm::join(assignments, _separator); | ||||||
|  | |||||||
| @ -174,11 +174,8 @@ string Predicate::formatSummaryCall(vector<smtutil::Expression> const& _args) co | |||||||
| 	auto const& params = fun->parameters(); | 	auto const& params = fun->parameters(); | ||||||
| 	solAssert(params.size() == functionArgsCex.size(), ""); | 	solAssert(params.size() == functionArgsCex.size(), ""); | ||||||
| 	for (unsigned i = 0; i < params.size(); ++i) | 	for (unsigned i = 0; i < params.size(); ++i) | ||||||
| 		if (params[i]->type()->isValueType()) | 		if (params.at(i) && functionArgsCex.at(i)) | ||||||
| 		{ |  | ||||||
| 			solAssert(functionArgsCex.at(i), ""); |  | ||||||
| 			functionArgs.emplace_back(*functionArgsCex.at(i)); | 			functionArgs.emplace_back(*functionArgsCex.at(i)); | ||||||
| 		} |  | ||||||
| 		else | 		else | ||||||
| 			functionArgs.emplace_back(params[i]->name()); | 			functionArgs.emplace_back(params[i]->name()); | ||||||
| 
 | 
 | ||||||
| @ -298,6 +295,76 @@ optional<string> Predicate::expressionToString(smtutil::Expression const& _expr, | |||||||
| 		solAssert(_expr.arguments.empty(), ""); | 		solAssert(_expr.arguments.empty(), ""); | ||||||
| 		return _expr.name; | 		return _expr.name; | ||||||
| 	} | 	} | ||||||
|  | 	if (smt::isArray(*_type)) | ||||||
|  | 	{ | ||||||
|  | 		auto const& arrayType = dynamic_cast<ArrayType const&>(*_type); | ||||||
|  | 		solAssert(_expr.name == "tuple_constructor", ""); | ||||||
|  | 		auto const& tupleSort = dynamic_cast<TupleSort const&>(*_expr.sort); | ||||||
|  | 		solAssert(tupleSort.components.size() == 2, ""); | ||||||
|  | 
 | ||||||
|  | 		auto length = stoul(_expr.arguments.at(1).name); | ||||||
|  | 		// Limit this counterexample size to 1k.
 | ||||||
|  | 		// Some OSs give you "unlimited" memory through swap and other virtual memory,
 | ||||||
|  | 		// so purely relying on bad_alloc being thrown is not a good idea.
 | ||||||
|  | 		// In that case, the array allocation might cause OOM and the program is killed.
 | ||||||
|  | 		if (length >= 1024) | ||||||
|  | 			return {}; | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			vector<string> array(length); | ||||||
|  | 			if (!fillArray(_expr.arguments.at(0), array, arrayType)) | ||||||
|  | 				return {}; | ||||||
|  | 			return "[" + boost::algorithm::join(array, ", ") + "]"; | ||||||
|  | 		} | ||||||
|  | 		catch (bad_alloc const&) | ||||||
|  | 		{ | ||||||
|  | 			// Solver gave a concrete array but length is too large.
 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return {}; | 	return {}; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | bool Predicate::fillArray(smtutil::Expression const& _expr, vector<string>& _array, ArrayType const& _type) const | ||||||
|  | { | ||||||
|  | 	// Base case
 | ||||||
|  | 	if (_expr.name == "const_array") | ||||||
|  | 	{ | ||||||
|  | 		auto length = _array.size(); | ||||||
|  | 		optional<string> elemStr = expressionToString(_expr.arguments.at(1), _type.baseType()); | ||||||
|  | 		if (!elemStr) | ||||||
|  | 			return false; | ||||||
|  | 		_array.clear(); | ||||||
|  | 		_array.resize(length, *elemStr); | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Recursive case.
 | ||||||
|  | 	if (_expr.name == "store") | ||||||
|  | 	{ | ||||||
|  | 		if (!fillArray(_expr.arguments.at(0), _array, _type)) | ||||||
|  | 			return false; | ||||||
|  | 		optional<string> indexStr = expressionToString(_expr.arguments.at(1), TypeProvider::uint256()); | ||||||
|  | 		if (!indexStr) | ||||||
|  | 			return false; | ||||||
|  | 		// Sometimes the solver assigns huge lengths that are not related,
 | ||||||
|  | 		// we should catch and ignore those.
 | ||||||
|  | 		unsigned index; | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			index = stoul(*indexStr); | ||||||
|  | 		} | ||||||
|  | 		catch (out_of_range const&) | ||||||
|  | 		{ | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 		optional<string> elemStr = expressionToString(_expr.arguments.at(2), _type.baseType()); | ||||||
|  | 		if (!elemStr) | ||||||
|  | 			return false; | ||||||
|  | 		if (index < _array.size()) | ||||||
|  | 			_array.at(index) = *elemStr; | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	solAssert(false, ""); | ||||||
|  | } | ||||||
|  | |||||||
| @ -128,6 +128,12 @@ private: | |||||||
| 	/// @returns a string representation of the SMT expression based on a Solidity type.
 | 	/// @returns a string representation of the SMT expression based on a Solidity type.
 | ||||||
| 	std::optional<std::string> expressionToString(smtutil::Expression const& _expr, TypePointer _type) const; | 	std::optional<std::string> expressionToString(smtutil::Expression const& _expr, TypePointer _type) const; | ||||||
| 
 | 
 | ||||||
|  | 	/// Recursively fills _array from _expr.
 | ||||||
|  | 	/// _expr should have the form `store(store(...(const_array(x_0), i_0, e_0), i_m, e_m), i_k, e_k)`.
 | ||||||
|  | 	/// @returns true if the construction worked,
 | ||||||
|  | 	/// and false if at least one element could not be built.
 | ||||||
|  | 	bool fillArray(smtutil::Expression const& _expr, std::vector<std::string>& _array, ArrayType const& _type) const; | ||||||
|  | 
 | ||||||
| 	/// The actual SMT expression.
 | 	/// The actual SMT expression.
 | ||||||
| 	smt::SymbolicFunctionVariable m_predicate; | 	smt::SymbolicFunctionVariable m_predicate; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,9 +7,7 @@ contract C { | |||||||
|     function f(bool b) public { |     function f(bool b) public { | ||||||
|         if (b) |         if (b) | ||||||
|             s.x[2] |= 1; |             s.x[2] |= 1; | ||||||
|         assert(s.x[2] != 1); | 		// Removed because of Spacer nondeterminism. | ||||||
|  |         //assert(s.x[2] != 1); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| // ---- |  | ||||||
| // Warning 6328: (173-192): CHC: Assertion violation might happen here. |  | ||||||
| // Warning 7812: (173-192): BMC: Assertion violation might happen here. |  | ||||||
|  | |||||||
| @ -17,7 +17,8 @@ contract C | |||||||
| 		// Should not fail since knowledge is erased only for mapping (uint => uint). | 		// Should not fail since knowledge is erased only for mapping (uint => uint). | ||||||
| 		assert(severalMaps8[0][0] == 42); | 		assert(severalMaps8[0][0] == 42); | ||||||
| 		// Should not fail since singleMap == severalMaps3d[0][0] is not possible. | 		// Should not fail since singleMap == severalMaps3d[0][0] is not possible. | ||||||
| 		assert(severalMaps3d[0][0][0] == 42); | 		// Removed because of Spacer nondeterminism. | ||||||
|  | 		//assert(severalMaps3d[0][0][0] == 42); | ||||||
| 		// Should fail since singleMap == map is possible. | 		// Should fail since singleMap == map is possible. | ||||||
| 		assert(map[0] == 42); | 		assert(map[0] == 42); | ||||||
| 	} | 	} | ||||||
| @ -26,4 +27,4 @@ contract C | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| // ---- | // ---- | ||||||
| // Warning 6328: (781-801): CHC: Assertion violation happens here. | // Warning 6328: (830-850): CHC: Assertion violation happens here. | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user