diff --git a/test/tools/ossfuzz/AbiV2IsabelleFuzzer.cpp b/test/tools/ossfuzz/AbiV2IsabelleFuzzer.cpp index 87b7fd9137f5..4d99890122f9 100644 --- a/test/tools/ossfuzz/AbiV2IsabelleFuzzer.cpp +++ b/test/tools/ossfuzz/AbiV2IsabelleFuzzer.cpp @@ -24,9 +24,14 @@ using namespace solidity::test::abiv2fuzzer; using namespace solidity::test; +using namespace solidity::util; +using namespace solidity; using namespace std; static constexpr size_t abiCoderHeapSize = 1024 * 512; +static evmc::VM evmone = evmc::VM{evmc_create_evmone()}; +/// Expected output value is decimal 0 +static vector const expectedOutput(32, 0); DEFINE_PROTO_FUZZER(Contract const& _contract) { @@ -43,13 +48,60 @@ DEFINE_PROTO_FUZZER(Contract const& _contract) string typeString = converter.isabelleTypeString(); string valueString = converter.isabelleValueString(); - std::cout << typeString << std::endl; - std::cout << valueString << std::endl; abicoder::ABICoder coder(abiCoderHeapSize); - if (!typeString.empty()) + if (!typeString.empty() && converter.coderFunction()) { auto [encodeStatus, encodedData] = coder.encode(typeString, valueString); solAssert(encodeStatus, "Isabelle abicoder fuzzer: Encoding failed"); + + // Raw runtime byte code generated by solidity + bytes byteCode; + string hexEncodedInput; + + try + { + // Compile contract generated by the proto fuzzer + SolidityCompilationFramework solCompilationFramework; + string contractName = ":C"; + byteCode = solCompilationFramework.compileContract(contractSource, contractName); + Json::Value methodIdentifiers = solCompilationFramework.getMethodIdentifiers(); + // We always call the second function from the list of alphabetically + // sorted interface functions + hexEncodedInput = (++methodIdentifiers.begin())->asString() + encodedData.substr(2, encodedData.size()); + } + // Ignore stack too deep errors during compilation + catch (solidity::evmasm::StackTooDeepException const&) + { + return; + } + + // We target the default EVM which is the latest + solidity::langutil::EVMVersion version; + EVMHost hostContext(version, evmone); + + // Deploy contract and signal failure if deployment failed + evmc::result createResult = AbiV2Utility::deployContract(hostContext, byteCode); + solAssert( + createResult.status_code == EVMC_SUCCESS, + "Proto ABIv2 Fuzzer: Contract creation failed" + ); + + // Execute test function and signal failure if EVM reverted or + // did not return expected output on successful execution. + evmc::result callResult = AbiV2Utility::executeContract( + hostContext, + fromHex(hexEncodedInput), + createResult.create_address + ); + + // We don't care about EVM One failures other than EVMC_REVERT + solAssert(callResult.status_code != EVMC_REVERT, "Proto ABIv2 fuzzer: EVM One reverted"); + if (callResult.status_code == EVMC_SUCCESS) + solAssert( + AbiV2Utility::isOutputExpected(callResult.output_data, callResult.output_size, expectedOutput), + "Proto ABIv2 fuzzer: ABIv2 coding failure found" + ); + } return; } diff --git a/test/tools/ossfuzz/CMakeLists.txt b/test/tools/ossfuzz/CMakeLists.txt index 3d205722b6d8..21d1e19dce2b 100644 --- a/test/tools/ossfuzz/CMakeLists.txt +++ b/test/tools/ossfuzz/CMakeLists.txt @@ -151,7 +151,7 @@ if (OSSFUZZ) protobuf-mutator.a protobuf.a abicoder - gmp + gmp.a ) set_target_properties(abiv2_isabelle_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) target_compile_options(abiv2_isabelle_ossfuzz PUBLIC ${COMPILE_OPTIONS} -Wno-sign-conversion -Wno-suggest-destructor-override -Wno-inconsistent-missing-destructor-override) diff --git a/test/tools/ossfuzz/abiV2Proto.proto b/test/tools/ossfuzz/abiV2Proto.proto index 886ca53f7c11..1afc031767f9 100644 --- a/test/tools/ossfuzz/abiV2Proto.proto +++ b/test/tools/ossfuzz/abiV2Proto.proto @@ -44,14 +44,8 @@ message ValueType { } } -// bytes/string -message DynamicByteArrayType { - enum DType { - BYTES = 0; - STRING = 1; - } - required DType type = 1; -} +// bytes +message DynamicByteArrayType {} message ArrayType { required Type t = 1; diff --git a/test/tools/ossfuzz/protoToAbiV2.cpp b/test/tools/ossfuzz/protoToAbiV2.cpp index 9ea528e1728b..47d3942bb040 100644 --- a/test/tools/ossfuzz/protoToAbiV2.cpp +++ b/test/tools/ossfuzz/protoToAbiV2.cpp @@ -830,10 +830,10 @@ string TypeVisitor::visit(ArrayType const& _type) return baseType + arrayBracket; } -string TypeVisitor::visit(DynamicByteArrayType const& _type) +string TypeVisitor::visit(DynamicByteArrayType const&) { m_isLastDynParamRightPadded = true; - m_baseType = bytesArrayTypeAsString(_type); + m_baseType = "bytes"; m_structTupleString.addTypeStringToTuple(m_baseType); return m_baseType; } @@ -967,7 +967,7 @@ pair AssignCheckVisitor::visit(DynamicByteArrayType const& _type string isabelleValue = ValueGetterVisitor{}.isabelleBytesValueAsString(value); m_valueStream.appendValue(isabelleValue); } - DataType dataType = _type.type() == DynamicByteArrayType::BYTES ? DataType::BYTES : DataType::STRING; + DataType dataType = DataType::BYTES; return assignAndCheckStringPair(m_varName, m_paramName, value, value, dataType); } @@ -1127,12 +1127,6 @@ string AssignCheckVisitor::checkString(string const& _ref, string const& _value, string checkPred; switch (_type) { - case DataType::STRING: - checkPred = Whiskers(R"(!bytesCompare(bytes(), ))") - ("varName", _ref) - ("value", _value) - .render(); - break; case DataType::BYTES: checkPred = Whiskers(R"(!bytesCompare(, ))") ("varName", _ref) @@ -1288,10 +1282,6 @@ std::string ValueGetterVisitor::variableLengthValueAsString( bool _isHexLiteral ) { - // TODO: Move this to caller -// solAssert(_numBytes >= 0 && _numBytes <= s_maxDynArrayLength, -// "Proto ABIv2 fuzzer: Invalid hex length" -// ); if (_numBytes == 0) return Whiskers(R"(hex"")") ("isHex", _isHexLiteral) diff --git a/test/tools/ossfuzz/protoToAbiV2.h b/test/tools/ossfuzz/protoToAbiV2.h index 4d7421de4284..a2be558e8c6a 100644 --- a/test/tools/ossfuzz/protoToAbiV2.h +++ b/test/tools/ossfuzz/protoToAbiV2.h @@ -154,6 +154,10 @@ class ProtoConverter std::string contractToString(Contract const& _input); std::string isabelleTypeString() const; std::string isabelleValueString() const; + bool coderFunction() const + { + return m_test == Contract_Test::Contract_Test_CALLDATA_CODER; + } private: enum class Delimiter { @@ -448,7 +452,6 @@ class AbiV2ProtoVisitor enum class DataType { BYTES, - STRING, VALUE, ARRAY }; @@ -537,17 +540,6 @@ class AbiV2ProtoVisitor else return v; } - - static std::string bytesArrayTypeAsString(DynamicByteArrayType const& _x) - { - switch (_x.type()) - { - case DynamicByteArrayType::BYTES: - return "bytes"; - case DynamicByteArrayType::STRING: - return "string"; - } - } protected: T visitValueType(ValueType const& _type) {