mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Filter false positives due to EVM errors.
Co-authored-by: Daniel Kirchner <daniel@ekpyron.org>
This commit is contained in:
		
							parent
							
								
									34c08ea2c6
								
							
						
					
					
						commit
						24f42c5541
					
				| @ -773,7 +773,7 @@ evmc::result EVMHost::resultWithGas( | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| void EVMHost::print_storage_at(evmc::address const& _addr, ostringstream& _os) | ||||
| void EVMHost::printStorageAt(evmc::address const& _addr, ostringstream& _os) | ||||
| { | ||||
| 	for (auto const& [slot, value]: get_address_storage(_addr)) | ||||
| 		if (get_storage(_addr, slot)) | ||||
| @ -786,9 +786,9 @@ StorageMap const& EVMHost::get_address_storage(evmc::address const& _addr) | ||||
| 	return accounts[_addr].storage; | ||||
| } | ||||
| 
 | ||||
| void EVMHost::print_call_records(std::ostringstream& _os) const noexcept | ||||
| void EVMHost::printCallRecords(std::ostringstream& _os) const noexcept | ||||
| { | ||||
| 	auto callKind = [](evmc_call_kind _kind) -> string | ||||
| 	static const auto callKind = [](evmc_call_kind _kind) -> string | ||||
| 	{ | ||||
| 		switch (_kind) | ||||
| 		{ | ||||
| @ -814,7 +814,7 @@ void EVMHost::print_call_records(std::ostringstream& _os) const noexcept | ||||
| 			<< endl; | ||||
| } | ||||
| 
 | ||||
| void EVMHost::print_selfdestruct_records(ostringstream& _os) const noexcept | ||||
| void EVMHost::printSelfdestructRecords(ostringstream& _os) const noexcept | ||||
| { | ||||
| 	for (auto const& record: recorded_selfdestructs) | ||||
| 		_os << "SELFDESTRUCT" | ||||
| @ -825,7 +825,7 @@ void EVMHost::print_selfdestruct_records(ostringstream& _os) const noexcept | ||||
| 			<< endl; | ||||
| } | ||||
| 
 | ||||
| void EVMHost::print_balance(evmc::address const& _addr, ostringstream& _os) const noexcept | ||||
| void EVMHost::printBalance(evmc::address const& _addr, ostringstream& _os) const noexcept | ||||
| { | ||||
| 	_os << "BALANCE " << convertFromEVMC(get_balance(_addr)) << endl; | ||||
| } | ||||
| @ -837,13 +837,13 @@ string EVMHost::dumpState(evmc::address _addr) | ||||
| 	// Print state and execution trace.
 | ||||
| 	if (account_exists(_addr)) | ||||
| 	{ | ||||
| 		print_storage_at(_addr, stateStream); | ||||
| 		print_balance(_addr, stateStream); | ||||
| 		printStorageAt(_addr, stateStream); | ||||
| 		printBalance(_addr, stateStream); | ||||
| 	} | ||||
| 	else | ||||
| 		print_selfdestruct_records(stateStream); | ||||
| 		printSelfdestructRecords(stateStream); | ||||
| 
 | ||||
| 	print_call_records(stateStream); | ||||
| 	printCallRecords(stateStream); | ||||
| 
 | ||||
| 	return stateStream.str(); | ||||
| } | ||||
|  | ||||
| @ -97,13 +97,13 @@ private: | ||||
| 	/// Records calls made via @param _message.
 | ||||
| 	void recordCalls(evmc_message const& _message) noexcept; | ||||
| 	/// Prints contents of storage at @param _addr to @param _os.
 | ||||
| 	void print_storage_at(evmc::address const& _addr, std::ostringstream& _os); | ||||
| 	void printStorageAt(evmc::address const& _addr, std::ostringstream& _os); | ||||
| 	/// Prints call summary to @param _os.
 | ||||
| 	void print_call_records(std::ostringstream& _os) const noexcept; | ||||
| 	void printCallRecords(std::ostringstream& _os) const noexcept; | ||||
| 	/// Print self destruct records to @param _os.
 | ||||
| 	void print_selfdestruct_records(std::ostringstream& _os) const noexcept; | ||||
| 	void printSelfdestructRecords(std::ostringstream& _os) const noexcept; | ||||
| 	/// Print balance of @param _addr to @param _os.
 | ||||
| 	void print_balance(evmc::address const& _addr, std::ostringstream& _os) const noexcept; | ||||
| 	void printBalance(evmc::address const& _addr, std::ostringstream& _os) const noexcept; | ||||
| 
 | ||||
| 	static evmc::result precompileECRecover(evmc_message const& _message) noexcept; | ||||
| 	static evmc::result precompileSha256(evmc_message const& _message) noexcept; | ||||
|  | ||||
| @ -49,6 +49,10 @@ static evmc::VM evmone = evmc::VM{evmc_create_evmone()}; | ||||
| 
 | ||||
| DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| { | ||||
| 	// Solidity creates an invalid instruction for subobjects, so we simply
 | ||||
| 	// ignore them in this fuzzer.
 | ||||
| 	if (_input.has_obj()) | ||||
| 		return; | ||||
| 	bool filterStatefulInstructions = true; | ||||
| 	bool filterUnboundedLoops = true; | ||||
| 	ProtoConverter converter( | ||||
| @ -95,17 +99,26 @@ DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| 	// If the fuzzer synthesized input does not contain the revert opcode which
 | ||||
| 	// we lazily check by string find, the EVM call should not revert.
 | ||||
| 	bool noRevertInSource = yul_source.find("revert") == string::npos; | ||||
| 	bool noInvalidInSource = yul_source.find("invalid") == string::npos; | ||||
| 	if (noInvalidInSource) | ||||
| 		solAssert( | ||||
| 			callResult.status_code != EVMC_INVALID_INSTRUCTION, | ||||
| 			"Invalid instruction." | ||||
| 		); | ||||
| 	if (noRevertInSource) | ||||
| 		solAssert( | ||||
| 			callResult.status_code != EVMC_REVERT, | ||||
| 			"SolidityEvmoneInterface: EVM One reverted" | ||||
| 		); | ||||
| 	// Out of gas errors are problematic because it is possible that the
 | ||||
| 	// optimizer makes them go away, making EVM state impossible to
 | ||||
| 	// compare in general.
 | ||||
| 	if (callResult.status_code == EVMC_OUT_OF_GAS) | ||||
| 	// Bail out on serious errors encountered during a call.
 | ||||
| 	if (YulEvmoneUtility{}.seriousCallError(callResult.status_code)) | ||||
| 		return; | ||||
| 
 | ||||
| 	solAssert( | ||||
| 		(callResult.status_code == EVMC_SUCCESS || | ||||
| 		(!noRevertInSource && callResult.status_code == EVMC_REVERT) || | ||||
| 		(!noInvalidInSource && callResult.status_code == EVMC_INVALID_INSTRUCTION)), | ||||
| 		"Unoptimised call failed." | ||||
| 	); | ||||
| 	ostringstream unoptimizedState; | ||||
| 	unoptimizedState << hostContext.dumpState(deployResult.create_address); | ||||
| 
 | ||||
| @ -135,10 +148,34 @@ DEFINE_PROTO_FUZZER(Program const& _input) | ||||
| 			callResultOpt.status_code != EVMC_REVERT, | ||||
| 			"SolidityEvmoneInterface: EVM One reverted" | ||||
| 		); | ||||
| 	if (noInvalidInSource) | ||||
| 		solAssert( | ||||
| 			callResultOpt.status_code != EVMC_INVALID_INSTRUCTION, | ||||
| 			"Invalid instruction." | ||||
| 		); | ||||
| 	solAssert( | ||||
| 		(callResultOpt.status_code == EVMC_SUCCESS || | ||||
| 		 (!noRevertInSource && callResultOpt.status_code == EVMC_REVERT) || | ||||
| 		 (!noInvalidInSource && callResultOpt.status_code == EVMC_INVALID_INSTRUCTION)), | ||||
| 		"Optimised call failed." | ||||
| 	); | ||||
| 	ostringstream optimizedState; | ||||
| 	optimizedState << hostContext.dumpState(deployResultOpt.create_address); | ||||
| 
 | ||||
| 	int64_t constexpr tolerance = 1000; | ||||
| 	if (callResult.gas_left > callResultOpt.gas_left) | ||||
| 		if (callResult.gas_left - callResultOpt.gas_left > tolerance) | ||||
| 		{ | ||||
| 			cout << "Gas differential " << callResult.gas_left - callResultOpt.gas_left << endl; | ||||
| 			cout << "Unoptimised bytecode" << endl; | ||||
| 			cout << util::toHex(unoptimisedByteCode) << endl; | ||||
| 			cout << "Optimised bytecode" << endl; | ||||
| 			cout << util::toHex(optimisedByteCode) << endl; | ||||
| 			solAssert(false, "Optimised code consumed more than +1000 gas."); | ||||
| 		} | ||||
| 
 | ||||
| 	solAssert( | ||||
| 		unoptimizedState.str() == optimizedState.str(), | ||||
| 		"Storage of unoptimised and optimised stack reused code do not match." | ||||
| 		"State of unoptimised and optimised stack reused code do not match." | ||||
| 	); | ||||
| } | ||||
|  | ||||
| @ -78,3 +78,21 @@ evmc_message YulEvmoneUtility::callMessage(evmc_address _address) | ||||
| 	call.kind = EVMC_CALL; | ||||
| 	return call; | ||||
| } | ||||
| 
 | ||||
| bool YulEvmoneUtility::seriousCallError(evmc_status_code _code) | ||||
| { | ||||
| 	if (_code == EVMC_OUT_OF_GAS) | ||||
| 		return true; | ||||
| 	else if (_code == EVMC_STACK_OVERFLOW) | ||||
| 		return true; | ||||
| 	else if (_code == EVMC_STACK_UNDERFLOW) | ||||
| 		return true; | ||||
| 	else if (_code == EVMC_INTERNAL_ERROR) | ||||
| 		return true; | ||||
| 	else if (_code == EVMC_UNDEFINED_INSTRUCTION) | ||||
| 		return true; | ||||
| 	else if (_code == EVMC_INVALID_MEMORY_ACCESS) | ||||
| 		return true; | ||||
| 	else | ||||
| 		return false; | ||||
| } | ||||
|  | ||||
| @ -54,5 +54,7 @@ struct YulEvmoneUtility | ||||
| 	static evmc::result deployCode(solidity::bytes const& _input, EVMHost& _host); | ||||
| 	/// @returns call message to be sent to @param _address.
 | ||||
| 	static evmc_message callMessage(evmc_address _address); | ||||
| 	/// @returns true if call result indicates a serious error, false otherwise.
 | ||||
| 	static bool seriousCallError(evmc_status_code _code); | ||||
| }; | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user