mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #7490 from ethereum/smt_constructor
[SMTChecker] Add support to constructors
This commit is contained in:
		
						commit
						912a0e2e4d
					
				| @ -6,6 +6,7 @@ Language Features: | ||||
| 
 | ||||
| 
 | ||||
| Compiler Features: | ||||
|  * SMTChecker: Add support to constructors including constructor inheritance. | ||||
|  * Yul: When compiling via Yul, string literals from the Solidity code are kept as string literals if every character is safely printable. | ||||
|  * Yul Optimizer: Perform loop-invariant code motion. | ||||
| 
 | ||||
|  | ||||
| @ -110,11 +110,6 @@ bool BMC::visit(ContractDefinition const& _contract) | ||||
| { | ||||
| 	initContract(_contract); | ||||
| 
 | ||||
| 	/// Check targets created by state variable initialization.
 | ||||
| 	smt::Expression constraints = m_context.assertions(); | ||||
| 	checkVerificationTargets(constraints); | ||||
| 	m_verificationTargets.clear(); | ||||
| 
 | ||||
| 	SMTEncoder::visit(_contract); | ||||
| 
 | ||||
| 	return false; | ||||
| @ -122,6 +117,17 @@ bool BMC::visit(ContractDefinition const& _contract) | ||||
| 
 | ||||
| void BMC::endVisit(ContractDefinition const& _contract) | ||||
| { | ||||
| 	if (auto constructor = _contract.constructor()) | ||||
| 		constructor->accept(*this); | ||||
| 	else | ||||
| 	{ | ||||
| 		inlineConstructorHierarchy(_contract); | ||||
| 		/// Check targets created by state variable initialization.
 | ||||
| 		smt::Expression constraints = m_context.assertions(); | ||||
| 		checkVerificationTargets(constraints); | ||||
| 		m_verificationTargets.clear(); | ||||
| 	} | ||||
| 
 | ||||
| 	SMTEncoder::endVisit(_contract); | ||||
| } | ||||
| 
 | ||||
| @ -132,10 +138,14 @@ bool BMC::visit(FunctionDefinition const& _function) | ||||
| 	solAssert(m_currentContract, ""); | ||||
| 	auto const& hierarchy = m_currentContract->annotation().linearizedBaseContracts; | ||||
| 	if (find(hierarchy.begin(), hierarchy.end(), contract) == hierarchy.end()) | ||||
| 		initializeStateVariables(*contract); | ||||
| 		createStateVariables(*contract); | ||||
| 
 | ||||
| 	if (m_callStack.empty()) | ||||
| 	{ | ||||
| 		reset(); | ||||
| 		initFunction(_function); | ||||
| 		resetStateVariables(); | ||||
| 	} | ||||
| 
 | ||||
| 	/// Already visits the children.
 | ||||
| 	SMTEncoder::visit(_function); | ||||
| @ -447,10 +457,6 @@ void BMC::inlineFunctionCall(FunctionCall const& _funCall) | ||||
| 		// The reason why we need to pushCallStack here instead of visit(FunctionDefinition)
 | ||||
| 		// is that there we don't have `_funCall`.
 | ||||
| 		pushCallStack({funDef, &_funCall}); | ||||
| 		// If an internal function is called to initialize
 | ||||
| 		// a state variable.
 | ||||
| 		if (m_callStack.empty()) | ||||
| 			initFunction(*funDef); | ||||
| 		funDef->accept(*this); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -65,6 +65,15 @@ void CHC::analyze(SourceUnit const& _source) | ||||
| 	m_context.setAssertionAccumulation(false); | ||||
| 	m_variableUsage.setFunctionInlining(false); | ||||
| 
 | ||||
| 	auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool); | ||||
| 	auto genesisSort = make_shared<smt::FunctionSort>( | ||||
| 		vector<smt::SortPointer>(), | ||||
| 		boolSort | ||||
| 	); | ||||
| 	m_genesisPredicate = createSymbolicBlock(genesisSort, "genesis"); | ||||
| 	auto genesis = (*m_genesisPredicate)({}); | ||||
| 	addRule(genesis, genesis.name); | ||||
| 
 | ||||
| 	_source.accept(*this); | ||||
| } | ||||
| 
 | ||||
| @ -94,10 +103,10 @@ bool CHC::visit(ContractDefinition const& _contract) | ||||
| 		else | ||||
| 			m_stateSorts.push_back(smt::smtSort(*var->type())); | ||||
| 
 | ||||
| 	clearIndices(); | ||||
| 	clearIndices(&_contract); | ||||
| 
 | ||||
| 	string interfaceName = "interface_" + _contract.name() + "_" + to_string(_contract.id()); | ||||
| 	m_interfacePredicate = createSymbolicBlock(interfaceSort(), interfaceName); | ||||
| 	string suffix = _contract.name() + "_" + to_string(_contract.id()); | ||||
| 	m_interfacePredicate = createSymbolicBlock(interfaceSort(), "interface_" + suffix); | ||||
| 
 | ||||
| 	// TODO create static instances for Bool/Int sorts in SolverInterface.
 | ||||
| 	auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool); | ||||
| @ -105,27 +114,11 @@ bool CHC::visit(ContractDefinition const& _contract) | ||||
| 		vector<smt::SortPointer>(), | ||||
| 		boolSort | ||||
| 	); | ||||
| 	m_errorPredicate = createSymbolicBlock(errorFunctionSort, "error"); | ||||
| 
 | ||||
| 	// If the contract has a constructor it is handled as a function.
 | ||||
| 	// Otherwise we zero-initialize all state vars.
 | ||||
| 	if (!_contract.constructor()) | ||||
| 	{ | ||||
| 		string constructorName = "constructor_" + _contract.name() + "_" + to_string(_contract.id()); | ||||
| 		m_constructorPredicate = createSymbolicBlock(constructorSort(), constructorName); | ||||
| 		smt::Expression constructorPred = (*m_constructorPredicate)({}); | ||||
| 		addRule(constructorPred, constructorName); | ||||
| 
 | ||||
| 		for (auto const& var: m_stateVariables) | ||||
| 		{ | ||||
| 			auto const& symbVar = m_context.variable(*var); | ||||
| 			symbVar->increaseIndex(); | ||||
| 			m_interface->declareVariable(symbVar->currentName(), symbVar->sort()); | ||||
| 			m_context.setZeroValue(*symbVar); | ||||
| 		} | ||||
| 
 | ||||
| 		connectBlocks(constructorPred, interface()); | ||||
| 	} | ||||
| 	m_errorPredicate = createSymbolicBlock(errorFunctionSort, "error_" + suffix); | ||||
| 	m_constructorPredicate = createSymbolicBlock(constructorSort(), "implicit_constructor_" + to_string(_contract.id())); | ||||
| 	auto stateExprs = currentStateVariables(); | ||||
| 	setCurrentBlock(*m_interfacePredicate, &stateExprs); | ||||
| 
 | ||||
| 	SMTEncoder::visit(_contract); | ||||
| 	return false; | ||||
| @ -136,6 +129,23 @@ void CHC::endVisit(ContractDefinition const& _contract) | ||||
| 	if (!shouldVisit(_contract)) | ||||
| 		return; | ||||
| 
 | ||||
| 	for (auto const& var: m_stateVariables) | ||||
| 	{ | ||||
| 		solAssert(m_context.knownVariable(*var), ""); | ||||
| 		m_context.setZeroValue(*var); | ||||
| 	} | ||||
| 	auto genesisPred = (*m_genesisPredicate)({}); | ||||
| 	auto implicitConstructor = (*m_constructorPredicate)(currentStateVariables()); | ||||
| 	connectBlocks(genesisPred, implicitConstructor); | ||||
| 	m_currentBlock = implicitConstructor; | ||||
| 
 | ||||
| 	if (auto constructor = _contract.constructor()) | ||||
| 		constructor->accept(*this); | ||||
| 	else | ||||
| 		inlineConstructorHierarchy(_contract); | ||||
| 
 | ||||
| 	connectBlocks(m_currentBlock, interface()); | ||||
| 
 | ||||
| 	for (unsigned i = 0; i < m_verificationTargets.size(); ++i) | ||||
| 	{ | ||||
| 		auto const& target = m_verificationTargets.at(i); | ||||
| @ -152,6 +162,16 @@ bool CHC::visit(FunctionDefinition const& _function) | ||||
| 	if (!shouldVisit(_function)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	// This is the case for base constructor inlining.
 | ||||
| 	if (m_currentFunction) | ||||
| 	{ | ||||
| 		solAssert(m_currentFunction->isConstructor(), ""); | ||||
| 		solAssert(_function.isConstructor(), ""); | ||||
| 		solAssert(_function.scope() != m_currentContract, ""); | ||||
| 		SMTEncoder::visit(_function); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	solAssert(!m_currentFunction, "Inlining internal function calls not yet implemented"); | ||||
| 	m_currentFunction = &_function; | ||||
| 
 | ||||
| @ -163,20 +183,11 @@ bool CHC::visit(FunctionDefinition const& _function) | ||||
| 	auto functionPred = predicate(*functionEntryBlock, currentFunctionVariables()); | ||||
| 	auto bodyPred = predicate(*bodyBlock); | ||||
| 
 | ||||
| 	// Store the constraints related to variable initialization.
 | ||||
| 	smt::Expression const& initAssertions = m_context.assertions(); | ||||
| 	m_context.pushSolver(); | ||||
| 
 | ||||
| 	connectBlocks(interface(), functionPred); | ||||
| 	connectBlocks(m_currentBlock, functionPred); | ||||
| 	connectBlocks(functionPred, bodyPred); | ||||
| 
 | ||||
| 	m_context.popSolver(); | ||||
| 
 | ||||
| 	setCurrentBlock(*bodyBlock); | ||||
| 
 | ||||
| 	// We need to re-add the constraints that were created for initialization of variables.
 | ||||
| 	m_context.addAssertion(initAssertions); | ||||
| 
 | ||||
| 	SMTEncoder::visit(*m_currentFunction); | ||||
| 
 | ||||
| 	return false; | ||||
| @ -187,10 +198,37 @@ void CHC::endVisit(FunctionDefinition const& _function) | ||||
| 	if (!shouldVisit(_function)) | ||||
| 		return; | ||||
| 
 | ||||
| 	connectBlocks(m_currentBlock, interface()); | ||||
| 	// This is the case for base constructor inlining.
 | ||||
| 	if (m_currentFunction != &_function) | ||||
| 	{ | ||||
| 		solAssert(m_currentFunction && m_currentFunction->isConstructor(), ""); | ||||
| 		solAssert(_function.isConstructor(), ""); | ||||
| 		solAssert(_function.scope() != m_currentContract, ""); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// We create an extra exit block for constructors that simply
 | ||||
| 		// connects to the interface in case an explicit constructor
 | ||||
| 		// exists in the hierarchy.
 | ||||
| 		// It is not connected directly here, as normal functions are,
 | ||||
| 		// because of the case where there are only implicit constructors.
 | ||||
| 		// This is done in endVisit(ContractDefinition).
 | ||||
| 		if (_function.isConstructor()) | ||||
| 		{ | ||||
| 			auto constructorExit = createBlock(&_function, "exit_"); | ||||
| 			connectBlocks(m_currentBlock, predicate(*constructorExit)); | ||||
| 			setCurrentBlock(*constructorExit); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			connectBlocks(m_currentBlock, interface()); | ||||
| 			clearIndices(m_currentContract, m_currentFunction); | ||||
| 			auto stateExprs = currentStateVariables(); | ||||
| 			setCurrentBlock(*m_interfacePredicate, &stateExprs); | ||||
| 		} | ||||
| 		m_currentFunction = nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	solAssert(&_function == m_currentFunction, ""); | ||||
| 	m_currentFunction = nullptr; | ||||
| 	SMTEncoder::endVisit(_function); | ||||
| } | ||||
| 
 | ||||
| @ -445,7 +483,6 @@ void CHC::reset() | ||||
| 	m_verificationTargets.clear(); | ||||
| 	m_safeAssertions.clear(); | ||||
| 	m_unknownFunctionCallSeen = false; | ||||
| 	m_blockCounter = 0; | ||||
| 	m_breakDest = nullptr; | ||||
| 	m_continueDest = nullptr; | ||||
| } | ||||
| @ -470,28 +507,31 @@ bool CHC::shouldVisit(FunctionDefinition const& _function) const | ||||
| { | ||||
| 	if ( | ||||
| 		_function.isPublic() && | ||||
| 		_function.isImplemented() && | ||||
| 		!_function.isConstructor() | ||||
| 		_function.isImplemented() | ||||
| 	) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| void CHC::setCurrentBlock(smt::SymbolicFunctionVariable const& _block) | ||||
| void CHC::setCurrentBlock( | ||||
| 	smt::SymbolicFunctionVariable const& _block, | ||||
| 	vector<smt::Expression> const* _arguments | ||||
| ) | ||||
| { | ||||
| 	m_context.popSolver(); | ||||
| 	clearIndices(); | ||||
| 	solAssert(m_currentContract, ""); | ||||
| 	clearIndices(m_currentContract, m_currentFunction); | ||||
| 	m_context.pushSolver(); | ||||
| 	m_currentBlock = predicate(_block); | ||||
| 	if (_arguments) | ||||
| 		m_currentBlock = predicate(_block, *_arguments); | ||||
| 	else | ||||
| 		m_currentBlock = predicate(_block); | ||||
| } | ||||
| 
 | ||||
| smt::SortPointer CHC::constructorSort() | ||||
| { | ||||
| 	solAssert(m_currentContract, ""); | ||||
| 	auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool); | ||||
| 	if (!m_currentContract->constructor()) | ||||
| 		return make_shared<smt::FunctionSort>(vector<smt::SortPointer>{}, boolSort); | ||||
| 	return sort(*m_currentContract->constructor()); | ||||
| 	// TODO this will change once we support function calls.
 | ||||
| 	return interfaceSort(); | ||||
| } | ||||
| 
 | ||||
| smt::SortPointer CHC::interfaceSort() | ||||
| @ -556,19 +596,6 @@ unique_ptr<smt::SymbolicFunctionVariable> CHC::createSymbolicBlock(smt::SortPoin | ||||
| 	return block; | ||||
| } | ||||
| 
 | ||||
| smt::Expression CHC::constructor() | ||||
| { | ||||
| 	solAssert(m_currentContract, ""); | ||||
| 
 | ||||
| 	if (!m_currentContract->constructor()) | ||||
| 		return (*m_constructorPredicate)({}); | ||||
| 
 | ||||
| 	vector<smt::Expression> paramExprs; | ||||
| 	for (auto const& var: m_currentContract->constructor()->parameters()) | ||||
| 		paramExprs.push_back(m_context.variable(*var)->currentValue()); | ||||
| 	return (*m_constructorPredicate)(paramExprs); | ||||
| } | ||||
| 
 | ||||
| smt::Expression CHC::interface() | ||||
| { | ||||
| 	vector<smt::Expression> paramExprs; | ||||
| @ -613,37 +640,31 @@ void CHC::connectBlocks(smt::Expression const& _from, smt::Expression const& _to | ||||
| 	addRule(edge, _from.name + "_to_" + _to.name); | ||||
| } | ||||
| 
 | ||||
| vector<smt::Expression> CHC::currentStateVariables() | ||||
| { | ||||
| 	solAssert(m_currentContract, ""); | ||||
| 	vector<smt::Expression> exprs; | ||||
| 	for (auto const& var: m_stateVariables) | ||||
| 		exprs.push_back(m_context.variable(*var)->currentValue()); | ||||
| 	return exprs; | ||||
| } | ||||
| 
 | ||||
| vector<smt::Expression> CHC::currentFunctionVariables() | ||||
| { | ||||
| 	solAssert(m_currentFunction, ""); | ||||
| 	vector<smt::Expression> paramExprs; | ||||
| 	for (auto const& var: m_stateVariables) | ||||
| 		paramExprs.push_back(m_context.variable(*var)->currentValue()); | ||||
| 	for (auto const& var: m_currentFunction->parameters() + m_currentFunction->returnParameters()) | ||||
| 		paramExprs.push_back(m_context.variable(*var)->currentValue()); | ||||
| 	return paramExprs; | ||||
| 	if (m_currentFunction) | ||||
| 		for (auto const& var: m_currentFunction->parameters() + m_currentFunction->returnParameters()) | ||||
| 			paramExprs.push_back(m_context.variable(*var)->currentValue()); | ||||
| 	return currentStateVariables() + paramExprs; | ||||
| } | ||||
| 
 | ||||
| vector<smt::Expression> CHC::currentBlockVariables() | ||||
| { | ||||
| 	solAssert(m_currentFunction, ""); | ||||
| 	vector<smt::Expression> paramExprs; | ||||
| 	for (auto const& var: m_currentFunction->localVariables()) | ||||
| 		paramExprs.push_back(m_context.variable(*var)->currentValue()); | ||||
| 	return currentFunctionVariables() + paramExprs; | ||||
| } | ||||
| 
 | ||||
| void CHC::clearIndices() | ||||
| { | ||||
| 	for (auto const& var: m_stateVariables) | ||||
| 		m_context.variable(*var)->resetIndex(); | ||||
| 	if (m_currentFunction) | ||||
| 	{ | ||||
| 		for (auto const& var: m_currentFunction->parameters() + m_currentFunction->returnParameters()) | ||||
| 			m_context.variable(*var)->resetIndex(); | ||||
| 		for (auto const& var: m_currentFunction->localVariables()) | ||||
| 			m_context.variable(*var)->resetIndex(); | ||||
| 	} | ||||
| 			paramExprs.push_back(m_context.variable(*var)->currentValue()); | ||||
| 	return currentFunctionVariables() + paramExprs; | ||||
| } | ||||
| 
 | ||||
| string CHC::predicateName(ASTNode const* _node) | ||||
| @ -674,7 +695,6 @@ smt::Expression CHC::predicate( | ||||
| 	return _block(_arguments); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void CHC::addRule(smt::Expression const& _rule, string const& _ruleName) | ||||
| { | ||||
| 	m_interface->addRule(_rule, _ruleName); | ||||
|  | ||||
| @ -83,7 +83,7 @@ private: | ||||
| 	void eraseKnowledge(); | ||||
| 	bool shouldVisit(ContractDefinition const& _contract) const; | ||||
| 	bool shouldVisit(FunctionDefinition const& _function) const; | ||||
| 	void setCurrentBlock(smt::SymbolicFunctionVariable const& _block); | ||||
| 	void setCurrentBlock(smt::SymbolicFunctionVariable const& _block, std::vector<smt::Expression> const* _arguments = nullptr); | ||||
| 	//@}
 | ||||
| 
 | ||||
| 	/// Sort helpers.
 | ||||
| @ -99,8 +99,6 @@ private: | ||||
| 	/// @returns a new block of given _sort and _name.
 | ||||
| 	std::unique_ptr<smt::SymbolicFunctionVariable> createSymbolicBlock(smt::SortPointer _sort, std::string const& _name); | ||||
| 
 | ||||
| 	/// Constructor predicate over current variables.
 | ||||
| 	smt::Expression constructor(); | ||||
| 	/// Interface predicate over current variables.
 | ||||
| 	smt::Expression interface(); | ||||
| 	/// Error predicate over current variables.
 | ||||
| @ -116,17 +114,16 @@ private: | ||||
| 
 | ||||
| 	void connectBlocks(smt::Expression const& _from, smt::Expression const& _to, smt::Expression const& _constraints = smt::Expression(true)); | ||||
| 
 | ||||
| 	/// @returns the current symbolic values of the current state variables.
 | ||||
| 	std::vector<smt::Expression> currentStateVariables(); | ||||
| 
 | ||||
| 	/// @returns the current symbolic values of the current function's
 | ||||
| 	/// input and output parameters.
 | ||||
| 	std::vector<smt::Expression> currentFunctionVariables(); | ||||
| 	/// @returns the samve as currentFunctionVariables plus
 | ||||
| 	/// @returns the same as currentFunctionVariables plus
 | ||||
| 	/// local variables.
 | ||||
| 	std::vector<smt::Expression> currentBlockVariables(); | ||||
| 
 | ||||
| 	/// Sets the SSA indices of the variables in scope to 0.
 | ||||
| 	/// Used when starting a new block.
 | ||||
| 	void clearIndices(); | ||||
| 
 | ||||
| 	/// @returns the predicate name for a given node.
 | ||||
| 	std::string predicateName(ASTNode const* _node); | ||||
| 	/// @returns a predicate application over the current scoped variables.
 | ||||
| @ -152,8 +149,11 @@ private: | ||||
| 
 | ||||
| 	/// Predicates.
 | ||||
| 	//@{
 | ||||
| 	/// Constructor predicate.
 | ||||
| 	/// Default constructor sets state vars to 0.
 | ||||
| 	/// Genesis predicate.
 | ||||
| 	std::unique_ptr<smt::SymbolicFunctionVariable> m_genesisPredicate; | ||||
| 
 | ||||
| 	/// Implicit constructor predicate.
 | ||||
| 	/// Explicit constructors are handled as functions.
 | ||||
| 	std::unique_ptr<smt::SymbolicFunctionVariable> m_constructorPredicate; | ||||
| 
 | ||||
| 	/// Artificial Interface predicate.
 | ||||
|  | ||||
| @ -22,6 +22,7 @@ | ||||
| #include <libsolidity/formal/SymbolicTypes.h> | ||||
| 
 | ||||
| #include <boost/range/adaptors.hpp> | ||||
| #include <boost/range/adaptor/reversed.hpp> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| @ -39,11 +40,28 @@ bool SMTEncoder::visit(ContractDefinition const& _contract) | ||||
| 	solAssert(m_currentContract, ""); | ||||
| 
 | ||||
| 	for (auto const& node: _contract.subNodes()) | ||||
| 		if (!dynamic_pointer_cast<FunctionDefinition>(node)) | ||||
| 		if ( | ||||
| 			!dynamic_pointer_cast<FunctionDefinition>(node) && | ||||
| 			!dynamic_pointer_cast<VariableDeclaration>(node) | ||||
| 		) | ||||
| 			node->accept(*this); | ||||
| 
 | ||||
| 	vector<FunctionDefinition const*> resolvedFunctions = _contract.definedFunctions(); | ||||
| 	for (auto const& base: _contract.annotation().linearizedBaseContracts) | ||||
| 	{ | ||||
| 		// Look for all the constructor invocations bottom up.
 | ||||
| 		if (auto const& constructor =  base->constructor()) | ||||
| 			for (auto const& invocation: constructor->modifiers()) | ||||
| 			{ | ||||
| 				auto refDecl = invocation->name()->annotation().referencedDeclaration; | ||||
| 				if (auto const& baseContract = dynamic_cast<ContractDefinition const*>(refDecl)) | ||||
| 				{ | ||||
| 					solAssert(!m_baseConstructorCalls.count(baseContract), ""); | ||||
| 					m_baseConstructorCalls[baseContract] = invocation.get(); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 		// Check for function overrides.
 | ||||
| 		for (auto const& baseFunction: base->definedFunctions()) | ||||
| 		{ | ||||
| 			if (baseFunction->isConstructor()) | ||||
| @ -62,9 +80,18 @@ bool SMTEncoder::visit(ContractDefinition const& _contract) | ||||
| 			if (!overridden) | ||||
| 				resolvedFunctions.push_back(baseFunction); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Functions are visited first since they might be used
 | ||||
| 	// for state variable initialization which is part of
 | ||||
| 	// the constructor.
 | ||||
| 	// Constructors are visited as part of the constructor
 | ||||
| 	// hierarchy inlining.
 | ||||
| 	for (auto const& function: resolvedFunctions) | ||||
| 		function->accept(*this); | ||||
| 		if (!function->isConstructor()) | ||||
| 			function->accept(*this); | ||||
| 
 | ||||
| 	// Constructors need to be handled by the engines separately.
 | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| @ -73,13 +100,16 @@ void SMTEncoder::endVisit(ContractDefinition const& _contract) | ||||
| { | ||||
| 	m_context.resetAllVariables(); | ||||
| 
 | ||||
| 	m_baseConstructorCalls.clear(); | ||||
| 
 | ||||
| 	solAssert(m_currentContract == &_contract, ""); | ||||
| 	m_currentContract = nullptr; | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::endVisit(VariableDeclaration const& _varDecl) | ||||
| { | ||||
| 	if (_varDecl.isLocalVariable() && _varDecl.type()->isValueType() &&_varDecl.value()) | ||||
| 	// State variables are handled by the constructor.
 | ||||
| 	if (_varDecl.isLocalVariable() &&_varDecl.value()) | ||||
| 		assignment(_varDecl, *_varDecl.value()); | ||||
| } | ||||
| 
 | ||||
| @ -90,25 +120,22 @@ bool SMTEncoder::visit(ModifierDefinition const&) | ||||
| 
 | ||||
| bool SMTEncoder::visit(FunctionDefinition const& _function) | ||||
| { | ||||
| 	// Not visited by a function call
 | ||||
| 	if (m_callStack.empty()) | ||||
| 		initFunction(_function); | ||||
| 
 | ||||
| 	m_modifierDepthStack.push_back(-1); | ||||
| 
 | ||||
| 	if (_function.isConstructor()) | ||||
| 	{ | ||||
| 		m_errorReporter.warning( | ||||
| 			_function.location(), | ||||
| 			"Assertion checker does not yet support constructors." | ||||
| 		); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		_function.parameterList().accept(*this); | ||||
| 		if (_function.returnParameterList()) | ||||
| 			_function.returnParameterList()->accept(*this); | ||||
| 		visitFunctionOrModifier(); | ||||
| 	} | ||||
| 		inlineConstructorHierarchy(dynamic_cast<ContractDefinition const&>(*_function.scope())); | ||||
| 
 | ||||
| 	// Base constructors' parameters should be set by explicit calls,
 | ||||
| 	// but the most derived one needs to be initialized.
 | ||||
| 	if (_function.scope() == m_currentContract) | ||||
| 		initializeLocalVariables(_function); | ||||
| 
 | ||||
| 	_function.parameterList().accept(*this); | ||||
| 	if (_function.returnParameterList()) | ||||
| 		_function.returnParameterList()->accept(*this); | ||||
| 
 | ||||
| 	visitFunctionOrModifier(); | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| @ -130,27 +157,87 @@ void SMTEncoder::visitFunctionOrModifier() | ||||
| 		solAssert(m_modifierDepthStack.back() < int(function.modifiers().size()), ""); | ||||
| 		ASTPointer<ModifierInvocation> const& modifierInvocation = function.modifiers()[m_modifierDepthStack.back()]; | ||||
| 		solAssert(modifierInvocation, ""); | ||||
| 		modifierInvocation->accept(*this); | ||||
| 		auto const& modifierDef = dynamic_cast<ModifierDefinition const&>( | ||||
| 			*modifierInvocation->name()->annotation().referencedDeclaration | ||||
| 		); | ||||
| 		vector<smt::Expression> modifierArgsExpr; | ||||
| 		if (auto const* arguments = modifierInvocation->arguments()) | ||||
| 		{ | ||||
| 			auto const& modifierParams = modifierDef.parameters(); | ||||
| 			solAssert(modifierParams.size() == arguments->size(), ""); | ||||
| 			for (unsigned i = 0; i < arguments->size(); ++i) | ||||
| 				modifierArgsExpr.push_back(expr(*arguments->at(i), modifierParams.at(i)->type())); | ||||
| 		} | ||||
| 		initializeFunctionCallParameters(modifierDef, modifierArgsExpr); | ||||
| 		pushCallStack({&modifierDef, modifierInvocation.get()}); | ||||
| 		modifierDef.body().accept(*this); | ||||
| 		popCallStack(); | ||||
| 		auto refDecl = modifierInvocation->name()->annotation().referencedDeclaration; | ||||
| 		if (dynamic_cast<ContractDefinition const*>(refDecl)) | ||||
| 			visitFunctionOrModifier(); | ||||
| 		else if (auto modifierDef = dynamic_cast<ModifierDefinition const*>(refDecl)) | ||||
| 			inlineModifierInvocation(modifierInvocation.get(), modifierDef); | ||||
| 		else | ||||
| 			solAssert(false, ""); | ||||
| 	} | ||||
| 
 | ||||
| 	--m_modifierDepthStack.back(); | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::inlineModifierInvocation(ModifierInvocation const* _invocation, CallableDeclaration const* _definition) | ||||
| { | ||||
| 	solAssert(_invocation, ""); | ||||
| 	_invocation->accept(*this); | ||||
| 
 | ||||
| 	vector<smt::Expression> args; | ||||
| 	if (auto const* arguments = _invocation->arguments()) | ||||
| 	{ | ||||
| 		auto const& modifierParams = _definition->parameters(); | ||||
| 		solAssert(modifierParams.size() == arguments->size(), ""); | ||||
| 		for (unsigned i = 0; i < arguments->size(); ++i) | ||||
| 			args.push_back(expr(*arguments->at(i), modifierParams.at(i)->type())); | ||||
| 	} | ||||
| 
 | ||||
| 	initializeFunctionCallParameters(*_definition, args); | ||||
| 
 | ||||
| 	pushCallStack({_definition, _invocation}); | ||||
| 	if (auto modifier = dynamic_cast<ModifierDefinition const*>(_definition)) | ||||
| 	{ | ||||
| 		modifier->body().accept(*this); | ||||
| 		popCallStack(); | ||||
| 	} | ||||
| 	else if (auto function = dynamic_cast<FunctionDefinition const*>(_definition)) | ||||
| 	{ | ||||
| 		if (function->isImplemented()) | ||||
| 			function->accept(*this); | ||||
| 		// Functions are popped from the callstack in endVisit(FunctionDefinition)
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::inlineConstructorHierarchy(ContractDefinition const& _contract) | ||||
| { | ||||
| 	auto const& hierarchy = m_currentContract->annotation().linearizedBaseContracts; | ||||
| 	auto it = find(begin(hierarchy), end(hierarchy), &_contract); | ||||
| 	solAssert(it != end(hierarchy), ""); | ||||
| 
 | ||||
| 	auto nextBase = it + 1; | ||||
| 	// Initialize the base contracts here as long as their constructors are implicit,
 | ||||
| 	// stop when the first explicit constructor is found.
 | ||||
| 	while (nextBase != end(hierarchy)) | ||||
| 	{ | ||||
| 		if (auto baseConstructor = (*nextBase)->constructor()) | ||||
| 		{ | ||||
| 			createLocalVariables(*baseConstructor); | ||||
| 			// If any subcontract explicitly called baseConstructor, use those arguments.
 | ||||
| 			if (m_baseConstructorCalls.count(*nextBase)) | ||||
| 				inlineModifierInvocation(m_baseConstructorCalls.at(*nextBase), baseConstructor); | ||||
| 			else if (baseConstructor->isImplemented()) | ||||
| 			{ | ||||
| 				// The first constructor found is handled like a function
 | ||||
| 				// and its pushed into the callstack there.
 | ||||
| 				// This if avoids duplication in the callstack.
 | ||||
| 				if (!m_callStack.empty()) | ||||
| 					pushCallStack({baseConstructor, nullptr}); | ||||
| 				baseConstructor->accept(*this); | ||||
| 				// popped by endVisit(FunctionDefinition)
 | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			initializeStateVariables(**nextBase); | ||||
| 			++nextBase; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	initializeStateVariables(_contract); | ||||
| } | ||||
| 
 | ||||
| bool SMTEncoder::visit(PlaceholderStatement const&) | ||||
| { | ||||
| 	solAssert(!m_callStack.empty(), ""); | ||||
| @ -551,20 +638,25 @@ void SMTEncoder::initContract(ContractDefinition const& _contract) | ||||
| 	solAssert(m_currentContract == nullptr, ""); | ||||
| 	m_currentContract = &_contract; | ||||
| 
 | ||||
| 	initializeStateVariables(_contract); | ||||
| 	m_context.reset(); | ||||
| 	m_context.pushSolver(); | ||||
| 	createStateVariables(_contract); | ||||
| 	clearIndices(m_currentContract, nullptr); | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::initFunction(FunctionDefinition const& _function) | ||||
| { | ||||
| 	solAssert(m_callStack.empty(), ""); | ||||
| 	solAssert(m_currentContract, ""); | ||||
| 	m_context.reset(); | ||||
| 	m_context.pushSolver(); | ||||
| 	m_pathConditions.clear(); | ||||
| 	pushCallStack({&_function, nullptr}); | ||||
| 	m_uninterpretedTerms.clear(); | ||||
| 	resetStateVariables(); | ||||
| 	initializeLocalVariables(_function); | ||||
| 	createStateVariables(*m_currentContract); | ||||
| 	createLocalVariables(_function); | ||||
| 	m_arrayAssignmentHappened = false; | ||||
| 	clearIndices(m_currentContract, &_function); | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::visitAssert(FunctionCall const& _funCall) | ||||
| @ -1239,26 +1331,61 @@ void SMTEncoder::initializeFunctionCallParameters(CallableDeclaration const& _fu | ||||
| 			} | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::initializeStateVariables(ContractDefinition const& _contract) | ||||
| void SMTEncoder::createStateVariables(ContractDefinition const& _contract) | ||||
| { | ||||
| 	for (auto var: _contract.stateVariablesIncludingInherited()) | ||||
| 		createVariable(*var); | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::initializeLocalVariables(FunctionDefinition const& _function) | ||||
| void SMTEncoder::initializeStateVariables(ContractDefinition const& _contract) | ||||
| { | ||||
| 	for (auto var: _contract.stateVariables()) | ||||
| 	{ | ||||
| 		solAssert(m_context.knownVariable(*var), ""); | ||||
| 		m_context.setZeroValue(*var); | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto var: _contract.stateVariables()) | ||||
| 		if (var->value()) | ||||
| 		{ | ||||
| 			var->value()->accept(*this); | ||||
| 			assignment(*var, *var->value()); | ||||
| 		} | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::createLocalVariables(FunctionDefinition const& _function) | ||||
| { | ||||
| 	for (auto const& variable: _function.localVariables()) | ||||
| 		if (createVariable(*variable)) | ||||
| 			m_context.setZeroValue(*variable); | ||||
| 		createVariable(*variable); | ||||
| 
 | ||||
| 	for (auto const& param: _function.parameters()) | ||||
| 		if (createVariable(*param)) | ||||
| 			m_context.setUnknownValue(*param); | ||||
| 		createVariable(*param); | ||||
| 
 | ||||
| 	if (_function.returnParameterList()) | ||||
| 		for (auto const& retParam: _function.returnParameters()) | ||||
| 			if (createVariable(*retParam)) | ||||
| 				m_context.setZeroValue(*retParam); | ||||
| 			createVariable(*retParam); | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::initializeLocalVariables(FunctionDefinition const& _function) | ||||
| { | ||||
| 	for (auto const& variable: _function.localVariables()) | ||||
| 	{ | ||||
| 		solAssert(m_context.knownVariable(*variable), ""); | ||||
| 		m_context.setZeroValue(*variable); | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto const& param: _function.parameters()) | ||||
| 	{ | ||||
| 		solAssert(m_context.knownVariable(*param), ""); | ||||
| 		m_context.setUnknownValue(*param); | ||||
| 	} | ||||
| 
 | ||||
| 	if (_function.returnParameterList()) | ||||
| 		for (auto const& retParam: _function.returnParameters()) | ||||
| 		{ | ||||
| 			solAssert(m_context.knownVariable(*retParam), ""); | ||||
| 			m_context.setZeroValue(*retParam); | ||||
| 		} | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::resetStateVariables() | ||||
| @ -1438,6 +1565,20 @@ void SMTEncoder::resetVariableIndices(VariableIndices const& _indices) | ||||
| 		m_context.variable(*var.first)->index() = var.second; | ||||
| } | ||||
| 
 | ||||
| void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function) | ||||
| { | ||||
| 	solAssert(_contract, ""); | ||||
| 	for (auto var: _contract->stateVariablesIncludingInherited()) | ||||
| 		m_context.variable(*var)->resetIndex(); | ||||
| 	if (_function) | ||||
| 	{ | ||||
| 		for (auto const& var: _function->parameters() + _function->returnParameters()) | ||||
| 			m_context.variable(*var)->resetIndex(); | ||||
| 		for (auto const& var: _function->localVariables()) | ||||
| 			m_context.variable(*var)->resetIndex(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| Expression const* SMTEncoder::leftmostBase(IndexAccess const& _indexAccess) | ||||
| { | ||||
| 	Expression const* base = &_indexAccess.baseExpression(); | ||||
|  | ||||
| @ -122,6 +122,12 @@ protected: | ||||
| 	/// visit depth.
 | ||||
| 	void visitFunctionOrModifier(); | ||||
| 
 | ||||
| 	/// Inlines a modifier or base constructor call.
 | ||||
| 	void inlineModifierInvocation(ModifierInvocation const* _invocation, CallableDeclaration const* _definition); | ||||
| 
 | ||||
| 	/// Inlines the constructor hierarchy into a single constructor.
 | ||||
| 	void inlineConstructorHierarchy(ContractDefinition const& _contract); | ||||
| 
 | ||||
| 	/// Defines a new global variable or function.
 | ||||
| 	void defineGlobalVariable(std::string const& _name, Expression const& _expr, bool _increaseIndex = false); | ||||
| 
 | ||||
| @ -161,7 +167,9 @@ protected: | ||||
| 
 | ||||
| 	using CallStackEntry = std::pair<CallableDeclaration const*, ASTNode const*>; | ||||
| 
 | ||||
| 	void createStateVariables(ContractDefinition const& _contract); | ||||
| 	void initializeStateVariables(ContractDefinition const& _contract); | ||||
| 	void createLocalVariables(FunctionDefinition const& _function); | ||||
| 	void initializeLocalVariables(FunctionDefinition const& _function); | ||||
| 	void initializeFunctionCallParameters(CallableDeclaration const& _function, std::vector<smt::Expression> const& _callArgs); | ||||
| 	void resetStateVariables(); | ||||
| @ -209,6 +217,9 @@ protected: | ||||
| 	VariableIndices copyVariableIndices(); | ||||
| 	/// Resets the variable indices.
 | ||||
| 	void resetVariableIndices(VariableIndices const& _indices); | ||||
| 	/// Used when starting a new block.
 | ||||
| 	void clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function = nullptr); | ||||
| 
 | ||||
| 
 | ||||
| 	/// @returns variables that are touched in _node's subtree.
 | ||||
| 	std::set<VariableDeclaration const*> touchedVariables(ASTNode const& _node); | ||||
| @ -253,6 +264,8 @@ protected: | ||||
| 	/// Needs to be a stack because of function calls.
 | ||||
| 	std::vector<int> m_modifierDepthStack; | ||||
| 
 | ||||
| 	std::map<ContractDefinition const*, ModifierInvocation const*> m_baseConstructorCalls; | ||||
| 
 | ||||
| 	ContractDefinition const* m_currentContract = nullptr; | ||||
| 
 | ||||
| 	/// Stores the context of the encoding.
 | ||||
|  | ||||
| @ -53,6 +53,5 @@ contract MyConc{ | ||||
| // ---- | ||||
| // Warning: (773-792): This declaration shadows an existing declaration. | ||||
| // Warning: (1009-1086): Function state mutability can be restricted to view | ||||
| // Warning: (874-879): Underflow (resulting value less than 0) happens here. | ||||
| // Warning: (874-879): Overflow (resulting value larger than 2**256 - 1) happens here. | ||||
| // Warning: (985-1002): Underflow (resulting value less than 0) happens here. | ||||
| // Warning: (985-1002): Overflow (resulting value larger than 2**256 - 1) happens here. | ||||
|  | ||||
| @ -137,4 +137,3 @@ contract PropagateThroughReturnValue { | ||||
| // Warning: (748-755): Assertion checker does not yet support this expression. | ||||
| // Warning: (748-751): Assertion checker does not yet implement type struct Reference.St storage pointer | ||||
| // Warning: (748-770): Assertion checker does not yet implement such assignments. | ||||
| // Warning: (849-905): Assertion checker does not yet support constructors. | ||||
|  | ||||
| @ -13,5 +13,3 @@ contract B is A { | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (56-90): Assertion checker does not yet support constructors. | ||||
| // Warning: (113-151): Assertion checker does not yet support constructors. | ||||
|  | ||||
| @ -1,6 +1,16 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { constructor(uint) public {} } | ||||
| contract A is C { constructor() C(2) public {} } | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is C { | ||||
| 	constructor() C(2) public { | ||||
| 		assert(a == 2); | ||||
| 		assert(a == 3); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (45-72): Assertion checker does not yet support constructors. | ||||
| // Warning: (93-121): Assertion checker does not yet support constructors. | ||||
| // Warning: (166-180): Assertion violation happens here | ||||
|  | ||||
| @ -1,10 +1,7 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { constructor(uint) public {} } | ||||
| contract A is C { constructor() C(2) public {} } | ||||
| contract B is C { constructor() C(3) public {} } | ||||
| contract J is C { constructor() C(3) public {} } | ||||
| contract C { uint a; constructor(uint x) public { a = x; } } | ||||
| contract A is C { constructor() C(2) public { assert(a == 2); } } | ||||
| contract B is C { constructor() C(3) public { assert(a == 3); } } | ||||
| contract J is C { constructor() C(3) public { assert(a == 4); } } | ||||
| // ---- | ||||
| // Warning: (45-72): Assertion checker does not yet support constructors. | ||||
| // Warning: (93-121): Assertion checker does not yet support constructors. | ||||
| // Warning: (142-170): Assertion checker does not yet support constructors. | ||||
| // Warning: (191-219): Assertion checker does not yet support constructors. | ||||
| // Warning: (271-285): Assertion violation happens here | ||||
|  | ||||
| @ -0,0 +1,22 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B is C { | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| 	constructor(uint x) B(x) C(x + 2) public { | ||||
| 		assert(a == x); | ||||
| 		assert(a == x + 1); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (244-262): Assertion violation happens here | ||||
| @ -0,0 +1,23 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B is C { | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| 	constructor(uint x) C(x + 2) B(x + 1) public { | ||||
| 		assert(a == x + 1); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (212-217): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (203-208): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (242-247): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| @ -0,0 +1,29 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B1 is C { | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B2 is C { | ||||
| 	constructor(uint x) C(x + 2) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B2, B1 { | ||||
| 	constructor(uint x) B2(x) B1(x) public { | ||||
| 		assert(a == x); | ||||
| 		assert(a == x + 1); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (205-210): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (321-339): Assertion violation happens here | ||||
| @ -0,0 +1,29 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B1 is C { | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B2 is C { | ||||
| 	constructor(uint x) C(x + 2) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B2, B1 { | ||||
| 	constructor(uint x) B1(x) B2(x) public { | ||||
| 		assert(a == x); | ||||
| 		assert(a == x + 1); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (205-210): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (321-339): Assertion violation happens here | ||||
| @ -0,0 +1,34 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B1 is C { | ||||
| 	uint b1; | ||||
| 	constructor(uint x) public { | ||||
| 		b1 = x + a; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B2 is C { | ||||
| 	uint b2; | ||||
| 	constructor(uint x) C(x + 2) public { | ||||
| 		b2 = x + a; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B2, B1 { | ||||
| 	constructor(uint x) B2(x) B1(x) public { | ||||
| 		assert(b1 == b2); | ||||
| 		assert(b1 != b2); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (165-170): Underflow (resulting value less than 0) happens here | ||||
| // Warning: (165-170): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (230-235): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (253-258): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (353-369): Assertion violation happens here | ||||
| @ -0,0 +1,23 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor() public { | ||||
| 		a = 2; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B is C { | ||||
| } | ||||
| 
 | ||||
| contract B2 is C { | ||||
| } | ||||
| 
 | ||||
| contract A is B, B2 { | ||||
| 	constructor(uint x) public { | ||||
| 		assert(a == 2); | ||||
| 		assert(a == 3); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (171-177): Unused function parameter. Remove or comment out the variable name to silence this warning. | ||||
| // Warning: (208-222): Assertion violation happens here | ||||
| @ -0,0 +1,19 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor() public { | ||||
| 		a = 2; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B is C { | ||||
| } | ||||
| 
 | ||||
| contract B2 is C { | ||||
| 	constructor() public { | ||||
| 		assert(a == 2); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B, B2 { | ||||
| } | ||||
| @ -0,0 +1,22 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract F { | ||||
| 	uint a; | ||||
| 	constructor() public { | ||||
| 		a = 2; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract E is F {} | ||||
| contract D is E {} | ||||
| contract C is D {} | ||||
| contract B is C {} | ||||
| 
 | ||||
| contract A is B { | ||||
| 	constructor(uint x) public { | ||||
| 		assert(a == 2); | ||||
| 		assert(a == 3); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (201-207): Unused function parameter. Remove or comment out the variable name to silence this warning. | ||||
| // Warning: (238-252): Assertion violation happens here | ||||
| @ -0,0 +1,20 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor() public { | ||||
| 		a = 2; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B is C { | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| 	constructor(uint x) B() public { | ||||
| 		assert(a == 2); | ||||
| 		assert(a == 3); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (145-151): Unused function parameter. Remove or comment out the variable name to silence this warning. | ||||
| // Warning: (186-200): Assertion violation happens here | ||||
| @ -0,0 +1,19 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor() public { | ||||
| 		a = 2; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B is C { | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| 	constructor(uint x) public { | ||||
| 		assert(a == 3); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (145-151): Unused function parameter. Remove or comment out the variable name to silence this warning. | ||||
| // Warning: (164-178): Assertion violation happens here | ||||
| @ -0,0 +1,30 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract F { | ||||
| 	uint a; | ||||
| 	constructor() public { | ||||
| 		a = 2; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract E is F {} | ||||
| contract D is E { | ||||
| 	constructor() public { | ||||
| 		a = 3; | ||||
| 	} | ||||
| } | ||||
| contract C is D {} | ||||
| contract B is C { | ||||
| 	constructor() public { | ||||
| 		a = 4; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| 	constructor(uint x) public { | ||||
| 		assert(a == 4); | ||||
| 		assert(a == 5); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (275-281): Unused function parameter. Remove or comment out the variable name to silence this warning. | ||||
| // Warning: (312-326): Assertion violation happens here | ||||
| @ -0,0 +1,24 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract F { | ||||
| 	uint a; | ||||
| 	constructor() public { | ||||
| 		a = 2; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract E is F {} | ||||
| contract D is E { | ||||
| 	constructor() public { | ||||
| 		a = 3; | ||||
| 	} | ||||
| } | ||||
| contract C is D {} | ||||
| contract B is C { | ||||
| 	constructor() public { | ||||
| 		assert(a == 3); | ||||
| 		a = 4; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| } | ||||
| @ -0,0 +1,29 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract F { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract E is F {} | ||||
| contract D is E { | ||||
| 	constructor() public { | ||||
| 		a = 3; | ||||
| 	} | ||||
| } | ||||
| contract C is D {} | ||||
| contract B is C { | ||||
| 	constructor(uint x) F(x + 1) public { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| 	constructor(uint x) B(x) public { | ||||
| 		assert(a == 3); | ||||
| 		assert(a == 4); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (234-239): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (329-343): Assertion violation happens here | ||||
| @ -0,0 +1,27 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract F { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract E is F {} | ||||
| contract D is E { | ||||
| 	constructor() public { | ||||
| 		a = 3; | ||||
| 	} | ||||
| } | ||||
| contract C is D {} | ||||
| contract B is C { | ||||
| 	constructor() F(1) public { | ||||
| 		assert(a == 3); | ||||
| 		assert(a == 2); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| } | ||||
| // ---- | ||||
| // Warning: (260-274): Assertion violation happens here | ||||
| // Warning: (260-274): Assertion violation happens here | ||||
| @ -0,0 +1,17 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	modifier n { _; a = 7; } | ||||
| 	constructor(uint x) n public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is C { | ||||
| 	modifier m { a = 5; _; } | ||||
| 	constructor() C(2) public { | ||||
| 		assert(a == 4); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (202-216): Assertion violation happens here | ||||
| @ -0,0 +1,16 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is C { | ||||
| 	constructor() C(2) public { | ||||
| 		assert(a == 0); | ||||
| 		assert(C.a == 0); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (148-162): Assertion violation happens here | ||||
| @ -0,0 +1,16 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract C { | ||||
| 	uint x; | ||||
| 
 | ||||
| 	constructor() public { | ||||
| 		assert(x == 0); | ||||
| 		x = 10; | ||||
| 	} | ||||
| 
 | ||||
| 	function f(uint y) public view { | ||||
| 		assert(y == x); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (148-162): Assertion violation happens here | ||||
| @ -0,0 +1,16 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract C { | ||||
| 	uint x = 5; | ||||
| 
 | ||||
| 	constructor() public { | ||||
| 		assert(x == 5); | ||||
| 		x = 10; | ||||
| 	} | ||||
| 
 | ||||
| 	function f(uint y) public view { | ||||
| 		assert(y == x); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (152-166): Assertion violation happens here | ||||
| @ -0,0 +1,18 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract B { | ||||
| 	uint x = 5; | ||||
| } | ||||
| 
 | ||||
| contract C is B { | ||||
| 	constructor() public { | ||||
| 		assert(x == 5); | ||||
| 		x = 10; | ||||
| 	} | ||||
| 
 | ||||
| 	function f(uint y) public view { | ||||
| 		assert(y == x); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (172-186): Assertion violation happens here | ||||
| @ -0,0 +1,17 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract C { | ||||
| 	uint x = 5; | ||||
| 
 | ||||
| 	constructor(uint a, uint b) public { | ||||
| 		assert(x == 5); | ||||
| 		x = a + b; | ||||
| 	} | ||||
| 
 | ||||
| 	function f(uint y) public view { | ||||
| 		assert(y == x); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (169-183): Assertion violation happens here | ||||
| // Warning: (122-127): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| @ -0,0 +1,29 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract F { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract E is F {} | ||||
| contract D is E { | ||||
| 	constructor() public { | ||||
| 		a = 3; | ||||
| 	} | ||||
| } | ||||
| contract C is D {} | ||||
| contract B is C { | ||||
| 	constructor(uint x) F(x + 1) public { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| 	constructor(uint x) B(x) public { | ||||
| 		assert(a == 3); | ||||
| 		assert(a == 4); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (234-239): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (329-343): Assertion violation happens here | ||||
| @ -0,0 +1,11 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract C { | ||||
| 	uint x = 2; | ||||
| 	constructor () public { | ||||
| 		assert(x == 2); | ||||
| 		assert(x == 3); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (104-118): Assertion violation happens here | ||||
| @ -0,0 +1,14 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract C { | ||||
| 	uint x = 2; | ||||
| } | ||||
| 
 | ||||
| contract D is C { | ||||
| 	constructor() public { | ||||
| 		assert(x == 2); | ||||
| 		assert(x == 3); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (124-138): Assertion violation happens here | ||||
| @ -0,0 +1,22 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract A { | ||||
| 	uint x = 1; | ||||
| } | ||||
| 
 | ||||
| contract B is A { | ||||
| 	constructor() public { x = 2; } | ||||
| } | ||||
| 
 | ||||
| contract C is B { | ||||
| 	constructor() public { x = 3; } | ||||
| } | ||||
| 
 | ||||
| contract D is C { | ||||
| 	constructor() public { | ||||
| 		assert(x == 3); | ||||
| 		assert(x == 2); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (232-246): Assertion violation happens here | ||||
| @ -0,0 +1,21 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract A { | ||||
| 	uint x = 1; | ||||
| } | ||||
| 
 | ||||
| contract B is A { | ||||
| 	constructor() public { x = 2; } | ||||
| } | ||||
| 
 | ||||
| contract C is B { | ||||
| } | ||||
| 
 | ||||
| contract D is C { | ||||
| 	constructor() public { | ||||
| 		assert(x == 2); | ||||
| 		assert(x == 3); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (199-213): Assertion violation happens here | ||||
| @ -0,0 +1,27 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B is C { | ||||
| 	uint b; | ||||
| 	constructor(uint x) public { | ||||
| 		b = a + x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| 	constructor(uint x) B(x) C(x + 2) public { | ||||
| 		assert(a == x + 2); | ||||
| 		assert(b == x + x + 2); | ||||
| 		assert(a == x + 5); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ---- | ||||
| // Warning: (162-167): Underflow (resulting value less than 0) happens here | ||||
| // Warning: (162-167): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (287-305): Assertion violation happens here | ||||
| @ -0,0 +1,26 @@ | ||||
| pragma experimental SMTChecker; | ||||
| contract C { | ||||
| 	uint a; | ||||
| 	constructor(uint x) public { | ||||
| 		a = x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B is C { | ||||
| 	uint b; | ||||
| 	constructor(uint x) public { | ||||
| 		b = x + 10; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract A is B { | ||||
| 	constructor(uint x) B(x) C(x + 2) public { | ||||
| 		assert(a == x + 2); | ||||
| 		assert(b == x + 10); | ||||
| 		assert(b == x + 5); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ---- | ||||
| // Warning: (162-168): Overflow (resulting value larger than 2**256 - 1) happens here | ||||
| // Warning: (285-303): Assertion violation happens here | ||||
| @ -0,0 +1,20 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract A { | ||||
| 	uint x = 2; | ||||
| } | ||||
| 
 | ||||
| contract B is A { | ||||
| } | ||||
| 
 | ||||
| contract C is A { | ||||
| } | ||||
| 
 | ||||
| contract D is B, C { | ||||
| 	constructor() public { | ||||
| 		assert(x == 2); | ||||
| 		assert(x == 3); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (169-183): Assertion violation happens here | ||||
| @ -0,0 +1,22 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract A { | ||||
| 	uint x = 1; | ||||
| } | ||||
| 
 | ||||
| contract B is A { | ||||
| 	constructor() public { x = 2; } | ||||
| } | ||||
| 
 | ||||
| contract C is A { | ||||
| 	constructor() public { x = 3; } | ||||
| } | ||||
| 
 | ||||
| contract D is B, C { | ||||
| 	constructor() public { | ||||
| 		assert(x == 3); | ||||
| 		assert(x == 4); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (235-249): Assertion violation happens here | ||||
| @ -0,0 +1,17 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract C { | ||||
| 	uint x = f(2); | ||||
| 	constructor () public { | ||||
| 		assert(x == 2); | ||||
| 	} | ||||
| 
 | ||||
| 	function f(uint y) internal view returns (uint) { | ||||
| 		assert(y > 0); | ||||
| 		assert(x == 0); | ||||
| 		return y; | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
| // Warning: (162-175): Assertion violation happens here | ||||
| // Warning: (179-193): Assertion violation happens here | ||||
| @ -15,7 +15,7 @@ contract A { | ||||
| // 2 warnings, B.f and A.g | ||||
| contract B is A { | ||||
| 	function f() public view { | ||||
| 		assert(x == 0); | ||||
| 		assert(x == 1); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
|  | ||||
| @ -17,7 +17,7 @@ contract B is A { | ||||
| 	uint y; | ||||
| 
 | ||||
| 	function f() public view { | ||||
| 		assert(x == 0); | ||||
| 		assert(x == 1); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
|  | ||||
| @ -17,10 +17,10 @@ contract B is A { | ||||
| 	uint y; | ||||
| 
 | ||||
| 	function f() public view { | ||||
| 		assert(x == 0); | ||||
| 		assert(x == 1); | ||||
| 	} | ||||
| 	function h() public view { | ||||
| 		assert(x == 2); | ||||
| 		assert(x == 1); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -29,10 +29,10 @@ contract C is B { | ||||
| 	uint z; | ||||
| 
 | ||||
| 	function f() public view { | ||||
| 		assert(x == 0); | ||||
| 		assert(x == 1); | ||||
| 	} | ||||
| 	function i() public view { | ||||
| 		assert(x == 0); | ||||
| 		assert(x == 1); | ||||
| 	} | ||||
| } | ||||
| // ---- | ||||
|  | ||||
| @ -0,0 +1,16 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract A { | ||||
| 	uint x; | ||||
| 	constructor (uint y) public { assert(x == 0); x = y; } | ||||
| } | ||||
| 
 | ||||
| contract B is A { | ||||
| 	constructor () A(2) public { assert(x == 2); } | ||||
| } | ||||
| 
 | ||||
| contract C is B { | ||||
| 	function f() public view { | ||||
| 		assert(x == 2); | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,20 @@ | ||||
| pragma experimental SMTChecker; | ||||
| 
 | ||||
| contract A { | ||||
| 	uint x; | ||||
| 	function h() public view { | ||||
| 		assert(x == 0); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract B is A { | ||||
| 	function g() public view { | ||||
| 		assert(x == 0); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| contract C is B { | ||||
| 	function f() public view { | ||||
| 		assert(x == 0); | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user