mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Abiv2 fuzzer: Enable differential fuzzing and remove support for string coding
co-authored-by: Leonardo <leo@ethereum.org>
This commit is contained in:
parent
39f1893956
commit
b273e52628
@ -24,9 +24,14 @@
|
|||||||
|
|
||||||
using namespace solidity::test::abiv2fuzzer;
|
using namespace solidity::test::abiv2fuzzer;
|
||||||
using namespace solidity::test;
|
using namespace solidity::test;
|
||||||
|
using namespace solidity::util;
|
||||||
|
using namespace solidity;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static constexpr size_t abiCoderHeapSize = 1024 * 512;
|
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)
|
DEFINE_PROTO_FUZZER(Contract const& _contract)
|
||||||
{
|
{
|
||||||
@ -43,13 +48,60 @@ DEFINE_PROTO_FUZZER(Contract const& _contract)
|
|||||||
|
|
||||||
string typeString = converter.isabelleTypeString();
|
string typeString = converter.isabelleTypeString();
|
||||||
string valueString = converter.isabelleValueString();
|
string valueString = converter.isabelleValueString();
|
||||||
std::cout << typeString << std::endl;
|
|
||||||
std::cout << valueString << std::endl;
|
|
||||||
abicoder::ABICoder coder(abiCoderHeapSize);
|
abicoder::ABICoder coder(abiCoderHeapSize);
|
||||||
if (!typeString.empty())
|
if (!typeString.empty() && converter.coderFunction())
|
||||||
{
|
{
|
||||||
auto [encodeStatus, encodedData] = coder.encode(typeString, valueString);
|
auto [encodeStatus, encodedData] = coder.encode(typeString, valueString);
|
||||||
solAssert(encodeStatus, "Isabelle abicoder fuzzer: Encoding failed");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ if (OSSFUZZ)
|
|||||||
protobuf-mutator.a
|
protobuf-mutator.a
|
||||||
protobuf.a
|
protobuf.a
|
||||||
abicoder
|
abicoder
|
||||||
gmp
|
gmp.a
|
||||||
)
|
)
|
||||||
set_target_properties(abiv2_isabelle_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
|
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)
|
target_compile_options(abiv2_isabelle_ossfuzz PUBLIC ${COMPILE_OPTIONS} -Wno-sign-conversion -Wno-suggest-destructor-override -Wno-inconsistent-missing-destructor-override)
|
||||||
|
@ -44,14 +44,8 @@ message ValueType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// bytes/string
|
// bytes
|
||||||
message DynamicByteArrayType {
|
message DynamicByteArrayType {}
|
||||||
enum DType {
|
|
||||||
BYTES = 0;
|
|
||||||
STRING = 1;
|
|
||||||
}
|
|
||||||
required DType type = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ArrayType {
|
message ArrayType {
|
||||||
required Type t = 1;
|
required Type t = 1;
|
||||||
|
@ -830,10 +830,10 @@ string TypeVisitor::visit(ArrayType const& _type)
|
|||||||
return baseType + arrayBracket;
|
return baseType + arrayBracket;
|
||||||
}
|
}
|
||||||
|
|
||||||
string TypeVisitor::visit(DynamicByteArrayType const& _type)
|
string TypeVisitor::visit(DynamicByteArrayType const&)
|
||||||
{
|
{
|
||||||
m_isLastDynParamRightPadded = true;
|
m_isLastDynParamRightPadded = true;
|
||||||
m_baseType = bytesArrayTypeAsString(_type);
|
m_baseType = "bytes";
|
||||||
m_structTupleString.addTypeStringToTuple(m_baseType);
|
m_structTupleString.addTypeStringToTuple(m_baseType);
|
||||||
return m_baseType;
|
return m_baseType;
|
||||||
}
|
}
|
||||||
@ -967,7 +967,7 @@ pair<string, string> AssignCheckVisitor::visit(DynamicByteArrayType const& _type
|
|||||||
string isabelleValue = ValueGetterVisitor{}.isabelleBytesValueAsString(value);
|
string isabelleValue = ValueGetterVisitor{}.isabelleBytesValueAsString(value);
|
||||||
m_valueStream.appendValue(isabelleValue);
|
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);
|
return assignAndCheckStringPair(m_varName, m_paramName, value, value, dataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1127,12 +1127,6 @@ string AssignCheckVisitor::checkString(string const& _ref, string const& _value,
|
|||||||
string checkPred;
|
string checkPred;
|
||||||
switch (_type)
|
switch (_type)
|
||||||
{
|
{
|
||||||
case DataType::STRING:
|
|
||||||
checkPred = Whiskers(R"(!bytesCompare(bytes(<varName>), <value>))")
|
|
||||||
("varName", _ref)
|
|
||||||
("value", _value)
|
|
||||||
.render();
|
|
||||||
break;
|
|
||||||
case DataType::BYTES:
|
case DataType::BYTES:
|
||||||
checkPred = Whiskers(R"(!bytesCompare(<varName>, <value>))")
|
checkPred = Whiskers(R"(!bytesCompare(<varName>, <value>))")
|
||||||
("varName", _ref)
|
("varName", _ref)
|
||||||
@ -1288,10 +1282,6 @@ std::string ValueGetterVisitor::variableLengthValueAsString(
|
|||||||
bool _isHexLiteral
|
bool _isHexLiteral
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// TODO: Move this to caller
|
|
||||||
// solAssert(_numBytes >= 0 && _numBytes <= s_maxDynArrayLength,
|
|
||||||
// "Proto ABIv2 fuzzer: Invalid hex length"
|
|
||||||
// );
|
|
||||||
if (_numBytes == 0)
|
if (_numBytes == 0)
|
||||||
return Whiskers(R"(<?isHex>hex</isHex>"")")
|
return Whiskers(R"(<?isHex>hex</isHex>"")")
|
||||||
("isHex", _isHexLiteral)
|
("isHex", _isHexLiteral)
|
||||||
|
@ -154,6 +154,10 @@ public:
|
|||||||
std::string contractToString(Contract const& _input);
|
std::string contractToString(Contract const& _input);
|
||||||
std::string isabelleTypeString() const;
|
std::string isabelleTypeString() const;
|
||||||
std::string isabelleValueString() const;
|
std::string isabelleValueString() const;
|
||||||
|
bool coderFunction() const
|
||||||
|
{
|
||||||
|
return m_test == Contract_Test::Contract_Test_CALLDATA_CODER;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
enum class Delimiter
|
enum class Delimiter
|
||||||
{
|
{
|
||||||
@ -448,7 +452,6 @@ public:
|
|||||||
enum class DataType
|
enum class DataType
|
||||||
{
|
{
|
||||||
BYTES,
|
BYTES,
|
||||||
STRING,
|
|
||||||
VALUE,
|
VALUE,
|
||||||
ARRAY
|
ARRAY
|
||||||
};
|
};
|
||||||
@ -537,17 +540,6 @@ public:
|
|||||||
else
|
else
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string bytesArrayTypeAsString(DynamicByteArrayType const& _x)
|
|
||||||
{
|
|
||||||
switch (_x.type())
|
|
||||||
{
|
|
||||||
case DynamicByteArrayType::BYTES:
|
|
||||||
return "bytes";
|
|
||||||
case DynamicByteArrayType::STRING:
|
|
||||||
return "string";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected:
|
protected:
|
||||||
T visitValueType(ValueType const& _type)
|
T visitValueType(ValueType const& _type)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user