diff --git a/test/tools/ossfuzz/abiV2FuzzerCommon.cpp b/test/tools/ossfuzz/abiV2FuzzerCommon.cpp index c9109ecdb..9e506b7d7 100644 --- a/test/tools/ossfuzz/abiV2FuzzerCommon.cpp +++ b/test/tools/ossfuzz/abiV2FuzzerCommon.cpp @@ -37,3 +37,46 @@ solidity::bytes SolidityCompilationFramework::compileContract( ); return obj.bytecode; } + +bool AbiV2Utility::isOutputExpected( + uint8_t const* _result, + size_t _length, + std::vector const& _expectedOutput +) +{ + if (_length != _expectedOutput.size()) + return false; + + return (memcmp(_result, _expectedOutput.data(), _length) == 0); +} + +evmc_message AbiV2Utility::initializeMessage(bytes const& _input) +{ + // Zero initialize all message fields + evmc_message msg = {}; + // Gas available (value of type int64_t) is set to its maximum + // value. + msg.gas = std::numeric_limits::max(); + msg.input_data = _input.data(); + msg.input_size = _input.size(); + return msg; +} + +evmc::result AbiV2Utility::executeContract( + EVMHost& _hostContext, + bytes const& _functionHash, + evmc_address _deployedAddress +) +{ + evmc_message message = initializeMessage(_functionHash); + message.destination = _deployedAddress; + message.kind = EVMC_CALL; + return _hostContext.call(message); +} + +evmc::result AbiV2Utility::deployContract(EVMHost& _hostContext, bytes const& _code) +{ + evmc_message message = initializeMessage(_code); + message.kind = EVMC_CREATE; + return _hostContext.call(message); +} \ No newline at end of file diff --git a/test/tools/ossfuzz/abiV2FuzzerCommon.h b/test/tools/ossfuzz/abiV2FuzzerCommon.h index e18458b77..d7e274dc4 100644 --- a/test/tools/ossfuzz/abiV2FuzzerCommon.h +++ b/test/tools/ossfuzz/abiV2FuzzerCommon.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -9,9 +11,10 @@ #include +#include + namespace solidity::test::abiv2fuzzer { - class SolidityCompilationFramework { public: @@ -32,4 +35,36 @@ protected: langutil::EVMVersion m_evmVersion; }; +struct AbiV2Utility +{ + /// Compares the contents of the memory address pointed to + /// by `_result` of `_length` bytes to the expected output. + /// Returns true if `_result` matches expected output, false + /// otherwise. + static bool isOutputExpected( + uint8_t const* _result, + size_t _length, + std::vector const& _expectedOutput + ); + /// Accepts a reference to a user-specified input and returns an + /// evmc_message with all of its fields zero initialized except + /// gas and input fields. + /// The gas field is set to the maximum permissible value so that we + /// don't run into out of gas errors. The input field is copied from + /// user input. + static evmc_message initializeMessage(bytes const& _input); + /// Accepts host context implementation, and keccak256 hash of the function + /// to be called at a specified address in the simulated blockchain as + /// input and returns the result of the execution of the called function. + static evmc::result executeContract( + EVMHost& _hostContext, + bytes const& _functionHash, + evmc_address _deployedAddress + ); + /// Accepts a reference to host context implementation and byte code + /// as input and deploys it on the simulated blockchain. Returns the + /// result of deployment. + static evmc::result deployContract(EVMHost& _hostContext, bytes const& _code); +}; + } diff --git a/test/tools/ossfuzz/abiV2ProtoFuzzer.cpp b/test/tools/ossfuzz/abiV2ProtoFuzzer.cpp index 8c529630f..c31ec8ee0 100644 --- a/test/tools/ossfuzz/abiV2ProtoFuzzer.cpp +++ b/test/tools/ossfuzz/abiV2ProtoFuzzer.cpp @@ -16,89 +16,26 @@ */ // SPDX-License-Identifier: GPL-3.0 -#include #include #include -#include #include #include -static evmc::VM evmone = evmc::VM{evmc_create_evmone()}; - using namespace solidity::test::abiv2fuzzer; using namespace solidity::test; using namespace solidity::util; using namespace solidity; using namespace std; -namespace -{ -/// Test function returns a uint256 value -static size_t const expectedOutputLength = 32; +static evmc::VM evmone = evmc::VM{evmc_create_evmone()}; /// Expected output value is decimal 0 -static uint8_t const expectedOutput[expectedOutputLength] = { +static vector const expectedOutput = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/// Compares the contents of the memory address pointed to -/// by `_result` of `_length` bytes to the expected output. -/// Returns true if `_result` matches expected output, false -/// otherwise. -bool isOutputExpected(uint8_t const* _result, size_t _length) -{ - if (_length != expectedOutputLength) - return false; - - return (memcmp(_result, expectedOutput, expectedOutputLength) == 0); -} - -/// Accepts a reference to a user-specified input and returns an -/// evmc_message with all of its fields zero initialized except -/// gas and input fields. -/// The gas field is set to the maximum permissible value so that we -/// don't run into out of gas errors. The input field is copied from -/// user input. -evmc_message initializeMessage(bytes const& _input) -{ - // Zero initialize all message fields - evmc_message msg = {}; - // Gas available (value of type int64_t) is set to its maximum - // value. - msg.gas = std::numeric_limits::max(); - msg.input_data = _input.data(); - msg.input_size = _input.size(); - return msg; -} - -/// Accepts host context implementation, and keccak256 hash of the function -/// to be called at a specified address in the simulated blockchain as -/// input and returns the result of the execution of the called function. -evmc::result executeContract( - EVMHost& _hostContext, - bytes const& _functionHash, - evmc_address _deployedAddress -) -{ - evmc_message message = initializeMessage(_functionHash); - message.destination = _deployedAddress; - message.kind = EVMC_CALL; - return _hostContext.call(message); -} - -/// Accepts a reference to host context implementation and byte code -/// as input and deploys it on the simulated blockchain. Returns the -/// result of deployment. -evmc::result deployContract(EVMHost& _hostContext, bytes const& _code) -{ - evmc_message message = initializeMessage(_code); - message.kind = EVMC_CREATE; - return _hostContext.call(message); -} -} - DEFINE_PROTO_FUZZER(Contract const& _input) { string contract_source = ProtoConverter{}.contractToString(_input); @@ -147,7 +84,7 @@ DEFINE_PROTO_FUZZER(Contract const& _input) EVMHost hostContext(version, evmone); // Deploy contract and signal failure if deploy failed - evmc::result createResult = deployContract(hostContext, byteCode); + evmc::result createResult = AbiV2Utility::deployContract(hostContext, byteCode); solAssert( createResult.status_code == EVMC_SUCCESS, "Proto ABIv2 Fuzzer: Contract creation failed" @@ -155,7 +92,7 @@ DEFINE_PROTO_FUZZER(Contract const& _input) // Execute test function and signal failure if EVM reverted or // did not return expected output on successful execution. - evmc::result callResult = executeContract( + evmc::result callResult = AbiV2Utility::executeContract( hostContext, fromHex(hexEncodedInput), createResult.create_address @@ -165,7 +102,7 @@ DEFINE_PROTO_FUZZER(Contract const& _input) solAssert(callResult.status_code != EVMC_REVERT, "Proto ABIv2 fuzzer: EVM One reverted"); if (callResult.status_code == EVMC_SUCCESS) solAssert( - isOutputExpected(callResult.output_data, callResult.output_size), + AbiV2Utility::isOutputExpected(callResult.output_data, callResult.output_size, expectedOutput), "Proto ABIv2 fuzzer: ABIv2 coding failure found" ); }