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;
|
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))
|
for (auto const& [slot, value]: get_address_storage(_addr))
|
||||||
if (get_storage(_addr, slot))
|
if (get_storage(_addr, slot))
|
||||||
@ -786,9 +786,9 @@ StorageMap const& EVMHost::get_address_storage(evmc::address const& _addr)
|
|||||||
return accounts[_addr].storage;
|
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)
|
switch (_kind)
|
||||||
{
|
{
|
||||||
@ -814,7 +814,7 @@ void EVMHost::print_call_records(std::ostringstream& _os) const noexcept
|
|||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EVMHost::print_selfdestruct_records(ostringstream& _os) const noexcept
|
void EVMHost::printSelfdestructRecords(ostringstream& _os) const noexcept
|
||||||
{
|
{
|
||||||
for (auto const& record: recorded_selfdestructs)
|
for (auto const& record: recorded_selfdestructs)
|
||||||
_os << "SELFDESTRUCT"
|
_os << "SELFDESTRUCT"
|
||||||
@ -825,7 +825,7 @@ void EVMHost::print_selfdestruct_records(ostringstream& _os) const noexcept
|
|||||||
<< endl;
|
<< 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;
|
_os << "BALANCE " << convertFromEVMC(get_balance(_addr)) << endl;
|
||||||
}
|
}
|
||||||
@ -837,13 +837,13 @@ string EVMHost::dumpState(evmc::address _addr)
|
|||||||
// Print state and execution trace.
|
// Print state and execution trace.
|
||||||
if (account_exists(_addr))
|
if (account_exists(_addr))
|
||||||
{
|
{
|
||||||
print_storage_at(_addr, stateStream);
|
printStorageAt(_addr, stateStream);
|
||||||
print_balance(_addr, stateStream);
|
printBalance(_addr, stateStream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
print_selfdestruct_records(stateStream);
|
printSelfdestructRecords(stateStream);
|
||||||
|
|
||||||
print_call_records(stateStream);
|
printCallRecords(stateStream);
|
||||||
|
|
||||||
return stateStream.str();
|
return stateStream.str();
|
||||||
}
|
}
|
||||||
|
@ -97,13 +97,13 @@ private:
|
|||||||
/// Records calls made via @param _message.
|
/// Records calls made via @param _message.
|
||||||
void recordCalls(evmc_message const& _message) noexcept;
|
void recordCalls(evmc_message const& _message) noexcept;
|
||||||
/// Prints contents of storage at @param _addr to @param _os.
|
/// 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.
|
/// 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.
|
/// 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.
|
/// 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 precompileECRecover(evmc_message const& _message) noexcept;
|
||||||
static evmc::result precompileSha256(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)
|
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 filterStatefulInstructions = true;
|
||||||
bool filterUnboundedLoops = true;
|
bool filterUnboundedLoops = true;
|
||||||
ProtoConverter converter(
|
ProtoConverter converter(
|
||||||
@ -95,17 +99,26 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
|||||||
// If the fuzzer synthesized input does not contain the revert opcode which
|
// If the fuzzer synthesized input does not contain the revert opcode which
|
||||||
// we lazily check by string find, the EVM call should not revert.
|
// we lazily check by string find, the EVM call should not revert.
|
||||||
bool noRevertInSource = yul_source.find("revert") == string::npos;
|
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)
|
if (noRevertInSource)
|
||||||
solAssert(
|
solAssert(
|
||||||
callResult.status_code != EVMC_REVERT,
|
callResult.status_code != EVMC_REVERT,
|
||||||
"SolidityEvmoneInterface: EVM One reverted"
|
"SolidityEvmoneInterface: EVM One reverted"
|
||||||
);
|
);
|
||||||
// Out of gas errors are problematic because it is possible that the
|
// Bail out on serious errors encountered during a call.
|
||||||
// optimizer makes them go away, making EVM state impossible to
|
if (YulEvmoneUtility{}.seriousCallError(callResult.status_code))
|
||||||
// compare in general.
|
|
||||||
if (callResult.status_code == EVMC_OUT_OF_GAS)
|
|
||||||
return;
|
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;
|
ostringstream unoptimizedState;
|
||||||
unoptimizedState << hostContext.dumpState(deployResult.create_address);
|
unoptimizedState << hostContext.dumpState(deployResult.create_address);
|
||||||
|
|
||||||
@ -135,10 +148,34 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
|||||||
callResultOpt.status_code != EVMC_REVERT,
|
callResultOpt.status_code != EVMC_REVERT,
|
||||||
"SolidityEvmoneInterface: EVM One reverted"
|
"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;
|
ostringstream optimizedState;
|
||||||
optimizedState << hostContext.dumpState(deployResultOpt.create_address);
|
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(
|
solAssert(
|
||||||
unoptimizedState.str() == optimizedState.str(),
|
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;
|
call.kind = EVMC_CALL;
|
||||||
return 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);
|
static evmc::result deployCode(solidity::bytes const& _input, EVMHost& _host);
|
||||||
/// @returns call message to be sent to @param _address.
|
/// @returns call message to be sent to @param _address.
|
||||||
static evmc_message callMessage(evmc_address _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