mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Analyze assembly.
This commit is contained in:
		
							parent
							
								
									7c61a6daf2
								
							
						
					
					
						commit
						d6861d909c
					
				| @ -207,6 +207,7 @@ bool SemanticInformation::invalidInPureFunctions(Instruction _instruction) | ||||
| 	case Instruction::NUMBER: | ||||
| 	case Instruction::DIFFICULTY: | ||||
| 	case Instruction::GASLIMIT: | ||||
| 	case Instruction::STATICCALL: | ||||
| 	case Instruction::SLOAD: | ||||
| 		return true; | ||||
| 	default: | ||||
|  | ||||
| @ -17,10 +17,86 @@ | ||||
| 
 | ||||
| #include <libsolidity/analysis/ViewPureChecker.h> | ||||
| 
 | ||||
| #include <libevmasm/SemanticInformation.h> | ||||
| 
 | ||||
| #include <libsolidity/inlineasm/AsmData.h> | ||||
| 
 | ||||
| #include <functional> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| using namespace dev::solidity; | ||||
| 
 | ||||
| 
 | ||||
| class AssemblyViewPureChecker: public boost::static_visitor<void> | ||||
| { | ||||
| public: | ||||
| 	explicit AssemblyViewPureChecker(std::function<void(StateMutability, SourceLocation const&)> _reportMutability): | ||||
| 		m_reportMutability(_reportMutability) {} | ||||
| 
 | ||||
| 	void operator()(assembly::Label const&) { } | ||||
| 	void operator()(assembly::Instruction const& _instruction) | ||||
| 	{ | ||||
| 		if (eth::SemanticInformation::invalidInViewFunctions(_instruction.instruction)) | ||||
| 			m_reportMutability(StateMutability::NonPayable, _instruction.location); | ||||
| 		else if (eth::SemanticInformation::invalidInPureFunctions(_instruction.instruction)) | ||||
| 			m_reportMutability(StateMutability::View, _instruction.location); | ||||
| 	} | ||||
| 	void operator()(assembly::Literal const&) {} | ||||
| 	void operator()(assembly::Identifier const&) {} | ||||
| 	void operator()(assembly::FunctionalInstruction const& _instr) | ||||
| 	{ | ||||
| 		(*this)(_instr.instruction); | ||||
| 		for (auto const& arg: _instr.arguments) | ||||
| 			boost::apply_visitor(*this, arg); | ||||
| 	} | ||||
| 	void operator()(assembly::StackAssignment const&) {} | ||||
| 	void operator()(assembly::Assignment const& _assignment) | ||||
| 	{ | ||||
| 		boost::apply_visitor(*this, *_assignment.value); | ||||
| 	} | ||||
| 	void operator()(assembly::VariableDeclaration const& _varDecl) | ||||
| 	{ | ||||
| 		if (_varDecl.value) | ||||
| 			boost::apply_visitor(*this, *_varDecl.value); | ||||
| 	} | ||||
| 	void operator()(assembly::FunctionDefinition const& _funDef) | ||||
| 	{ | ||||
| 		(*this)(_funDef.body); | ||||
| 	} | ||||
| 	void operator()(assembly::FunctionCall const& _funCall) | ||||
| 	{ | ||||
| 		for (auto const& arg: _funCall.arguments) | ||||
| 			boost::apply_visitor(*this, arg); | ||||
| 	} | ||||
| 	void operator()(assembly::Switch const& _switch) | ||||
| 	{ | ||||
| 		boost::apply_visitor(*this, *_switch.expression); | ||||
| 		for (auto const& _case: _switch.cases) | ||||
| 		{ | ||||
| 			if (_case.value) | ||||
| 				(*this)(*_case.value); | ||||
| 			(*this)(_case.body); | ||||
| 		} | ||||
| 	} | ||||
| 	void operator()(assembly::ForLoop const& _for) | ||||
| 	{ | ||||
| 		(*this)(_for.pre); | ||||
| 		boost::apply_visitor(*this, *_for.condition); | ||||
| 		(*this)(_for.body); | ||||
| 		(*this)(_for.post); | ||||
| 	} | ||||
| 	void operator()(assembly::Block const& _block) | ||||
| 	{ | ||||
| 		for (auto const& s: _block.statements) | ||||
| 			boost::apply_visitor(*this, s); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	std::function<void(StateMutability, SourceLocation const&)> m_reportMutability; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| bool ViewPureChecker::check() | ||||
| { | ||||
| 	vector<ContractDefinition const*> contracts; | ||||
| @ -122,16 +198,17 @@ void ViewPureChecker::endVisit(Identifier const& _identifier) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	reportMutability(mutability, _identifier); | ||||
| 	reportMutability(mutability, _identifier.location()); | ||||
| } | ||||
| 
 | ||||
| void ViewPureChecker::endVisit(InlineAssembly const& _inlineAssembly) | ||||
| { | ||||
| 	// @TOOD we can and should analyze it further.
 | ||||
| 	reportMutability(StateMutability::NonPayable, _inlineAssembly); | ||||
| 	AssemblyViewPureChecker{ | ||||
| 		[=](StateMutability _mut, SourceLocation const& _loc) { reportMutability(_mut, _loc); } | ||||
| 	}(_inlineAssembly.operations()); | ||||
| } | ||||
| 
 | ||||
| void ViewPureChecker::reportMutability(StateMutability _mutability, ASTNode const& _node) | ||||
| void ViewPureChecker::reportMutability(StateMutability _mutability, SourceLocation const& _location) | ||||
| { | ||||
| 	if (m_currentFunction && m_currentFunction->stateMutability() < _mutability) | ||||
| 	{ | ||||
| @ -151,11 +228,11 @@ void ViewPureChecker::reportMutability(StateMutability _mutability, ASTNode cons | ||||
| 
 | ||||
| 		if (m_currentFunction->stateMutability() == StateMutability::View) | ||||
| 			// Change this to error with 0.5.0
 | ||||
| 			m_errorReporter.warning(_node.location(), text); | ||||
| 			m_errorReporter.warning(_location, text); | ||||
| 		else if (m_currentFunction->stateMutability() == StateMutability::Pure) | ||||
| 		{ | ||||
| 			m_errors = true; | ||||
| 			m_errorReporter.typeError(_node.location(), text); | ||||
| 			m_errorReporter.typeError(_location, text); | ||||
| 		} | ||||
| 		else | ||||
| 			solAssert(false, ""); | ||||
| @ -173,7 +250,7 @@ void ViewPureChecker::endVisit(FunctionCall const& _functionCall) | ||||
| 	// We only require "nonpayable" to call a payble function.
 | ||||
| 	if (mut == StateMutability::Payable) | ||||
| 		mut = StateMutability::NonPayable; | ||||
| 	reportMutability(mut, _functionCall); | ||||
| 	reportMutability(mut, _functionCall.location()); | ||||
| } | ||||
| 
 | ||||
| void ViewPureChecker::endVisit(MemberAccess const& _memberAccess) | ||||
| @ -210,7 +287,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess) | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| 	reportMutability(mutability, _memberAccess); | ||||
| 	reportMutability(mutability, _memberAccess.location()); | ||||
| } | ||||
| 
 | ||||
| void ViewPureChecker::endVisit(IndexAccess const& _indexAccess) | ||||
| @ -219,7 +296,7 @@ void ViewPureChecker::endVisit(IndexAccess const& _indexAccess) | ||||
| 
 | ||||
| 	bool writes = _indexAccess.annotation().lValueRequested; | ||||
| 	if (_indexAccess.baseExpression().annotation().type->dataStoredIn(DataLocation::Storage)) | ||||
| 		reportMutability(writes ? StateMutability::NonPayable : StateMutability::View, _indexAccess); | ||||
| 		reportMutability(writes ? StateMutability::NonPayable : StateMutability::View, _indexAccess.location()); | ||||
| } | ||||
| 
 | ||||
| void ViewPureChecker::endVisit(ModifierInvocation const& _modifier) | ||||
| @ -229,6 +306,6 @@ void ViewPureChecker::endVisit(ModifierInvocation const& _modifier) | ||||
| 	solAssert(mod, ""); | ||||
| 	solAssert(m_inferredMutability.count(mod), ""); | ||||
| 
 | ||||
| 	reportMutability(m_inferredMutability.at(mod), _modifier); | ||||
| 	reportMutability(m_inferredMutability.at(mod), _modifier.location()); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -64,7 +64,7 @@ private: | ||||
| 
 | ||||
| 	/// Called when an element of mutability @a _mutability is encountered.
 | ||||
| 	/// Creates appropriate warnings and errors and sets @a m_currentBestMutability.
 | ||||
| 	void reportMutability(StateMutability _mutability, ASTNode const& _node); | ||||
| 	void reportMutability(StateMutability _mutability, SourceLocation const& _location); | ||||
| 
 | ||||
| 	std::vector<std::shared_ptr<ASTNode>> const& m_ast; | ||||
| 	ErrorReporter& m_errorReporter; | ||||
|  | ||||
| @ -5234,7 +5234,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_variable_access_out_of_functions) | ||||
| 	char const* text = R"( | ||||
| 		contract test { | ||||
| 			uint a; | ||||
| 			function f() { | ||||
| 			function f() pure { | ||||
| 				assembly { | ||||
| 					function g() -> x { x := a_slot } | ||||
| 				} | ||||
| @ -5921,7 +5921,7 @@ BOOST_AUTO_TEST_CASE(no_unused_inline_asm) | ||||
| { | ||||
| 	char const* text = R"( | ||||
| 		contract C { | ||||
| 			function f() { | ||||
| 			function f() pure { | ||||
| 				uint a; | ||||
| 				assembly { | ||||
| 					a := 1 | ||||
|  | ||||
| @ -316,6 +316,68 @@ BOOST_AUTO_TEST_CASE(function_types) | ||||
| 	CHECK_SUCCESS_NO_WARNINGS(text); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(creation) | ||||
| { | ||||
| 	string text = R"( | ||||
| 		contract D {} | ||||
| 		contract C { | ||||
| 			function f() { new D(); } | ||||
| 		} | ||||
| 	)"; | ||||
| 	CHECK_SUCCESS_NO_WARNINGS(text); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(assembly) | ||||
| { | ||||
| 	string text = R"( | ||||
| 		contract C { | ||||
| 			struct S { uint x; } | ||||
| 			S s; | ||||
| 			function e() pure { | ||||
| 				assembly { mstore(keccak256(0, 20), mul(s_slot, 2)) } | ||||
| 			} | ||||
| 			function f() pure { | ||||
| 				uint x; | ||||
| 				assembly { x := 7 } | ||||
| 			} | ||||
| 			function g() view { | ||||
| 				assembly { for {} 1 { pop(sload(0)) } { } } | ||||
| 			} | ||||
| 			function h() view { | ||||
| 				assembly { function g() { pop(blockhash(20)) } } | ||||
| 			} | ||||
| 			function j()  { | ||||
| 				assembly { pop(call(0, 1, 2, 3, 4, 5, 6)) } | ||||
| 			} | ||||
| 		} | ||||
| 	)"; | ||||
| 	CHECK_SUCCESS_NO_WARNINGS(text); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(assembly_staticcall) | ||||
| { | ||||
| 	string text = R"( | ||||
| 		contract C { | ||||
| 			function i() view { | ||||
| 				assembly { pop(staticcall(0, 1, 2, 3, 4, 5)) } | ||||
| 			} | ||||
| 		} | ||||
| 	)"; | ||||
| 	CHECK_WARNING(text, "only available after the Metropolis"); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(assembly_jump) | ||||
| { | ||||
| 	string text = R"( | ||||
| 		contract C { | ||||
| 			function k()  { | ||||
| 				assembly { jump(2) } | ||||
| 			} | ||||
| 		} | ||||
| 	)"; | ||||
| 	CHECK_WARNING(text, "low-level EVM features"); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user