mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #8173 from ethereum/fix-7859
yul proto fuzzer: Add EVM version field
This commit is contained in:
		
						commit
						a788ba14f3
					
				| @ -30,6 +30,7 @@ | ||||
| using namespace std; | ||||
| using namespace solidity::yul::test::yul_fuzzer; | ||||
| using namespace solidity::yul::test; | ||||
| using namespace solidity::langutil; | ||||
| using namespace solidity::util; | ||||
| using namespace solidity; | ||||
| 
 | ||||
| @ -86,6 +87,29 @@ string ProtoConverter::createAlphaNum(string const& _strBytes) | ||||
| 	return tmp; | ||||
| } | ||||
| 
 | ||||
| EVMVersion ProtoConverter::evmVersionMapping(Program_Version const& _ver) | ||||
| { | ||||
| 	switch (_ver) | ||||
| 	{ | ||||
| 	case Program::HOMESTEAD: | ||||
| 		return EVMVersion::homestead(); | ||||
| 	case Program::TANGERINE: | ||||
| 		return EVMVersion::tangerineWhistle(); | ||||
| 	case Program::SPURIOUS: | ||||
| 		return EVMVersion::spuriousDragon(); | ||||
| 	case Program::BYZANTIUM: | ||||
| 		return EVMVersion::byzantium(); | ||||
| 	case Program::CONSTANTINOPLE: | ||||
| 		return EVMVersion::constantinople(); | ||||
| 	case Program::PETERSBURG: | ||||
| 		return EVMVersion::petersburg(); | ||||
| 	case Program::ISTANBUL: | ||||
| 		return EVMVersion::istanbul(); | ||||
| 	case Program::BERLIN: | ||||
| 		return EVMVersion::berlin(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| string ProtoConverter::visit(Literal const& _x) | ||||
| { | ||||
| 	switch (_x.literal_oneof_case()) | ||||
| @ -230,7 +254,16 @@ void ProtoConverter::visit(Expression const& _x) | ||||
| 
 | ||||
| void ProtoConverter::visit(BinaryOp const& _x) | ||||
| { | ||||
| 	switch (_x.op()) | ||||
| 	BinaryOp_BOp op = _x.op(); | ||||
| 
 | ||||
| 	if ((op == BinaryOp::SHL || op == BinaryOp::SHR || op == BinaryOp::SAR) && | ||||
| 		!m_evmVersion.hasBitwiseShifting()) | ||||
| 	{ | ||||
| 		m_output << dictionaryToken(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (op) | ||||
| 	{ | ||||
| 	case BinaryOp::ADD: | ||||
| 		m_output << "add"; | ||||
| @ -266,12 +299,15 @@ void ProtoConverter::visit(BinaryOp const& _x) | ||||
| 		m_output << "gt"; | ||||
| 		break; | ||||
| 	case BinaryOp::SHR: | ||||
| 		yulAssert(m_evmVersion.hasBitwiseShifting(), "Proto fuzzer: Invalid evm version"); | ||||
| 		m_output << "shr"; | ||||
| 		break; | ||||
| 	case BinaryOp::SHL: | ||||
| 		yulAssert(m_evmVersion.hasBitwiseShifting(), "Proto fuzzer: Invalid evm version"); | ||||
| 		m_output << "shl"; | ||||
| 		break; | ||||
| 	case BinaryOp::SAR: | ||||
| 		yulAssert(m_evmVersion.hasBitwiseShifting(), "Proto fuzzer: Invalid evm version"); | ||||
| 		m_output << "sar"; | ||||
| 		break; | ||||
| 	case BinaryOp::SDIV: | ||||
| @ -475,7 +511,17 @@ void ProtoConverter::visit(TypedVarDecl const& _x) | ||||
| 
 | ||||
| void ProtoConverter::visit(UnaryOp const& _x) | ||||
| { | ||||
| 	switch (_x.op()) | ||||
| 	UnaryOp_UOp op = _x.op(); | ||||
| 
 | ||||
| 	// Replace calls to extcodehash on unsupported EVMs with a dictionary
 | ||||
| 	// token.
 | ||||
| 	if (op == UnaryOp::EXTCODEHASH && !m_evmVersion.hasExtCodeHash()) | ||||
| 	{ | ||||
| 		m_output << dictionaryToken(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (op) | ||||
| 	{ | ||||
| 	case UnaryOp::NOT: | ||||
| 		m_output << "not"; | ||||
| @ -550,7 +596,12 @@ void ProtoConverter::visit(NullaryOp const& _x) | ||||
| 		m_output << "codesize()"; | ||||
| 		break; | ||||
| 	case NullaryOp::RETURNDATASIZE: | ||||
| 		m_output << "returndatasize()"; | ||||
| 		// If evm supports returndatasize, we generate it. Otherwise,
 | ||||
| 		// we output a dictionary token.
 | ||||
| 		if (m_evmVersion.supportsReturndata()) | ||||
| 			m_output << "returndatasize()"; | ||||
| 		else | ||||
| 			m_output << dictionaryToken(); | ||||
| 		break; | ||||
| 	case NullaryOp::ADDRESS: | ||||
| 		m_output << "address()"; | ||||
| @ -583,10 +634,20 @@ void ProtoConverter::visit(NullaryOp const& _x) | ||||
| 		m_output << "gaslimit()"; | ||||
| 		break; | ||||
| 	case NullaryOp::SELFBALANCE: | ||||
| 		m_output << "selfbalance()"; | ||||
| 		// Replace calls to selfbalance() on unsupported EVMs with a dictionary
 | ||||
| 		// token.
 | ||||
| 		if (m_evmVersion.hasSelfBalance()) | ||||
| 			m_output << "selfbalance()"; | ||||
| 		else | ||||
| 			m_output << dictionaryToken(); | ||||
| 		break; | ||||
| 	case NullaryOp::CHAINID: | ||||
| 		m_output << "chainid()"; | ||||
| 		// Replace calls to chainid() on unsupported EVMs with a dictionary
 | ||||
| 		// token.
 | ||||
| 		if (m_evmVersion.hasChainID()) | ||||
| 			m_output << "chainid()"; | ||||
| 		else | ||||
| 			m_output << dictionaryToken(); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| @ -600,6 +661,11 @@ void ProtoConverter::visit(CopyFunc const& _x) | ||||
| 	if (type == CopyFunc::DATA && !m_isObject) | ||||
| 		return; | ||||
| 
 | ||||
| 	// We don't generate code if the copy function is returndatacopy
 | ||||
| 	// and the underlying evm does not support it.
 | ||||
| 	if (type == CopyFunc::RETURNDATA && !m_evmVersion.supportsReturndata()) | ||||
| 		return; | ||||
| 
 | ||||
| 	switch (type) | ||||
| 	{ | ||||
| 	case CopyFunc::CALLDATA: | ||||
| @ -609,6 +675,7 @@ void ProtoConverter::visit(CopyFunc const& _x) | ||||
| 		m_output << "codecopy"; | ||||
| 		break; | ||||
| 	case CopyFunc::RETURNDATA: | ||||
| 		yulAssert(m_evmVersion.supportsReturndata(), "Proto fuzzer: Invalid evm version"); | ||||
| 		m_output << "returndatacopy"; | ||||
| 		break; | ||||
| 	case CopyFunc::DATA: | ||||
| @ -890,6 +957,16 @@ void ProtoConverter::visit(FunctionCall const& _x) | ||||
| void ProtoConverter::visit(LowLevelCall const& _x) | ||||
| { | ||||
| 	LowLevelCall_Type type = _x.callty(); | ||||
| 
 | ||||
| 	// Generate staticcall if it is supported by the underlying evm
 | ||||
| 	if (type == LowLevelCall::STATICCALL && !m_evmVersion.hasStaticCall()) | ||||
| 	{ | ||||
| 		// Since staticcall is supposed to return 0 on success and 1 on
 | ||||
| 		// failure, we can use counter value to emulate it
 | ||||
| 		m_output << ((counter() % 2) ? "0" : "1"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (type) | ||||
| 	{ | ||||
| 	case LowLevelCall::CALL: | ||||
| @ -902,6 +979,7 @@ void ProtoConverter::visit(LowLevelCall const& _x) | ||||
| 		m_output << "delegatecall("; | ||||
| 		break; | ||||
| 	case LowLevelCall::STATICCALL: | ||||
| 		yulAssert(m_evmVersion.hasStaticCall(), "Proto fuzzer: Invalid evm version"); | ||||
| 		m_output << "staticcall("; | ||||
| 		break; | ||||
| 	} | ||||
| @ -927,6 +1005,15 @@ void ProtoConverter::visit(LowLevelCall const& _x) | ||||
| void ProtoConverter::visit(Create const& _x) | ||||
| { | ||||
| 	Create_Type type = _x.createty(); | ||||
| 
 | ||||
| 	// Replace a call to create2 on unsupported EVMs with a dictionary
 | ||||
| 	// token.
 | ||||
| 	if (type == Create::CREATE2 && !m_evmVersion.hasCreate2()) | ||||
| 	{ | ||||
| 		m_output << dictionaryToken(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (type) | ||||
| 	{ | ||||
| 	case Create::CREATE: | ||||
| @ -1653,7 +1740,8 @@ void ProtoConverter::createFunctionDefAndCall( | ||||
| 		!m_inForInitScope, | ||||
| 		"Proto fuzzer: Trying to create function call inside for-init block" | ||||
| 	); | ||||
| 	createFunctionCall(funcName, _numInParams, _numOutParams); | ||||
| 	if (_x.force_call()) | ||||
| 		createFunctionCall(funcName, _numInParams, _numOutParams); | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::visit(FunctionDef const& _x) | ||||
| @ -1737,6 +1825,9 @@ void ProtoConverter::visit(Program const& _x) | ||||
| 	// Initialize input size
 | ||||
| 	m_inputSize = _x.ByteSizeLong(); | ||||
| 
 | ||||
| 	// Record EVM Version
 | ||||
| 	m_evmVersion = evmVersionMapping(_x.ver()); | ||||
| 
 | ||||
| 	// Program is either a yul object or a block of
 | ||||
| 	// statements.
 | ||||
| 	switch (_x.program_oneof_case()) | ||||
|  | ||||
| @ -31,6 +31,8 @@ | ||||
| #include <libsolutil/FixedHash.h> | ||||
| #include <libsolutil/Whiskers.h> | ||||
| 
 | ||||
| #include <liblangutil/EVMVersion.h> | ||||
| 
 | ||||
| namespace solidity::yul::test::yul_fuzzer | ||||
| { | ||||
| class ProtoConverter | ||||
| @ -56,6 +58,12 @@ public: | ||||
| 	ProtoConverter(ProtoConverter&&) = delete; | ||||
| 	std::string programToString(Program const& _input); | ||||
| 
 | ||||
| 	/// Returns evm version
 | ||||
| 	solidity::langutil::EVMVersion version() | ||||
| 	{ | ||||
| 		return m_evmVersion; | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	void visit(BinaryOp const&); | ||||
| 
 | ||||
| @ -270,6 +278,10 @@ private: | ||||
| 	/// dictionarySize is the total number of entries in the dictionary.
 | ||||
| 	std::string dictionaryToken(util::HexPrefix _p = util::HexPrefix::Add); | ||||
| 
 | ||||
| 	/// Returns an EVMVersion object corresponding to the protobuf
 | ||||
| 	/// enum of type Program_Version
 | ||||
| 	solidity::langutil::EVMVersion evmVersionMapping(Program_Version const& _x); | ||||
| 
 | ||||
| 	/// Returns a monotonically increasing counter that starts from zero.
 | ||||
| 	unsigned counter() | ||||
| 	{ | ||||
| @ -367,5 +379,7 @@ private: | ||||
| 	/// Flag to track whether scope extension of variables defined in for-init
 | ||||
| 	/// block is enabled.
 | ||||
| 	bool m_forInitScopeExtEnabled; | ||||
| 	/// Object that holds the targeted evm version specified by protobuf input
 | ||||
| 	solidity::langutil::EVMVersion m_evmVersion; | ||||
| }; | ||||
| } | ||||
|  | ||||
| @ -355,6 +355,7 @@ message FunctionDef { | ||||
|   required uint32 num_input_params = 1; | ||||
|   required uint32 num_output_params = 2; | ||||
|   required Block block = 3; | ||||
|   required bool force_call = 4; | ||||
| } | ||||
| 
 | ||||
| message PopStmt { | ||||
| @ -405,10 +406,21 @@ message Data { | ||||
| } | ||||
| 
 | ||||
| message Program { | ||||
|   enum Version { | ||||
|     HOMESTEAD = 0; | ||||
|     TANGERINE = 1; | ||||
|     SPURIOUS = 2; | ||||
|     BYZANTIUM = 3; | ||||
|     CONSTANTINOPLE = 4; | ||||
|     PETERSBURG = 5; | ||||
|     ISTANBUL = 6; | ||||
|     BERLIN = 7; | ||||
|   } | ||||
|   oneof program_oneof { | ||||
|     Block block = 1; | ||||
|     Object obj = 2; | ||||
|   } | ||||
|   required Version ver = 3; | ||||
| } | ||||
| 
 | ||||
| package solidity.yul.test.yul_fuzzer; | ||||
|  | ||||
| @ -29,12 +29,14 @@ | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| using namespace solidity::yul::test::yul_fuzzer; | ||||
| using namespace solidity::langutil; | ||||
| using namespace std; | ||||
| 
 | ||||
| DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| { | ||||
| 	ProtoConverter converter; | ||||
| 	string yul_source = converter.programToString(_input); | ||||
| 	EVMVersion version = converter.version(); | ||||
| 
 | ||||
| 	if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) | ||||
| 	{ | ||||
| @ -51,7 +53,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| 
 | ||||
| 	// AssemblyStack entry point
 | ||||
| 	AssemblyStack stack( | ||||
| 		langutil::EVMVersion(), | ||||
| 		version, | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		solidity::frontend::OptimiserSettings::full() | ||||
| 	); | ||||
|  | ||||
| @ -55,7 +55,9 @@ void printErrors(ostream& _stream, ErrorList const& _errors) | ||||
| 
 | ||||
| DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| { | ||||
| 	string yul_source = ProtoConverter().programToString(_input); | ||||
| 	ProtoConverter converter; | ||||
| 	string yul_source = converter.programToString(_input); | ||||
| 	EVMVersion version = converter.version(); | ||||
| 
 | ||||
| 	if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH")) | ||||
| 	{ | ||||
| @ -69,7 +71,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| 
 | ||||
| 	// AssemblyStack entry point
 | ||||
| 	AssemblyStack stack( | ||||
| 		langutil::EVMVersion::berlin(), | ||||
| 		version, | ||||
| 		AssemblyStack::Language::StrictAssembly, | ||||
| 		solidity::frontend::OptimiserSettings::full() | ||||
| 	); | ||||
| @ -87,7 +89,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| 	yulFuzzerUtil::TerminationReason termReason = yulFuzzerUtil::interpret( | ||||
| 		os1, | ||||
| 		stack.parserResult()->code, | ||||
| 		EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion::berlin()) | ||||
| 		EVMDialect::strictAssemblyForEVMObjects(version) | ||||
| 	); | ||||
| 
 | ||||
| 	if (termReason == yulFuzzerUtil::TerminationReason::StepLimitReached) | ||||
| @ -97,7 +99,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| 	termReason = yulFuzzerUtil::interpret( | ||||
| 		os2, | ||||
| 		stack.parserResult()->code, | ||||
| 		EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion::berlin()), | ||||
| 		EVMDialect::strictAssemblyForEVMObjects(version), | ||||
| 		(yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 4) | ||||
| 	); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user