Abiv2 fuzzer: Enable differential fuzzing and remove support for string coding

co-authored-by: Leonardo <leo@ethereum.org>
This commit is contained in:
Bhargava Shastry 2020-12-14 14:27:05 +01:00
parent 39f1893956
commit b273e52628
5 changed files with 65 additions and 37 deletions

View File

@ -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<uint8_t> 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;
}

View File

@ -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)

View File

@ -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;

View File

@ -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<string, string> 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>), <value>))")
("varName", _ref)
("value", _value)
.render();
break;
case DataType::BYTES:
checkPred = Whiskers(R"(!bytesCompare(<varName>, <value>))")
("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"(<?isHex>hex</isHex>"")")
("isHex", _isHexLiteral)

View File

@ -154,6 +154,10 @@ public:
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 @@ public:
enum class DataType
{
BYTES,
STRING,
VALUE,
ARRAY
};
@ -537,17 +540,6 @@ public:
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)
{