mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add solidity protobuf based inheritance fuzzer
This commit is contained in:
parent
10879bcae6
commit
1d533694e5
@ -10,7 +10,7 @@ add_dependencies(ossfuzz
|
||||
|
||||
if (OSSFUZZ)
|
||||
add_custom_target(ossfuzz_proto)
|
||||
add_dependencies(ossfuzz_proto yul_proto_ossfuzz yul_proto_diff_ossfuzz)
|
||||
add_dependencies(ossfuzz_proto yul_proto_ossfuzz yul_proto_diff_ossfuzz sol_proto_ossfuzz)
|
||||
|
||||
add_custom_target(ossfuzz_abiv2)
|
||||
add_dependencies(ossfuzz_abiv2 abiv2_proto_ossfuzz)
|
||||
@ -60,6 +60,25 @@ if (OSSFUZZ)
|
||||
)
|
||||
set_target_properties(yul_proto_diff_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
|
||||
|
||||
# add_executable(yul_proto_diff_custom_mutate_ossfuzz
|
||||
# yulProto_diff_ossfuzz.cpp
|
||||
# yulFuzzerCommon.cpp
|
||||
# protoToYul.cpp
|
||||
# yulProto.pb.cc
|
||||
# protomutators/YulProtoMutator.cpp
|
||||
# )
|
||||
# target_include_directories(yul_proto_diff_custom_mutate_ossfuzz PRIVATE /usr/include/libprotobuf-mutator
|
||||
# /home/bhargava/work/github/solidity/deps/libprotobuf-mutator
|
||||
# /home/bhargava/work/github/solidity/deps/LPM/external.protobuf/include
|
||||
# )
|
||||
# target_link_libraries(yul_proto_diff_custom_mutate_ossfuzz PRIVATE yul
|
||||
# yulInterpreter
|
||||
# protobuf-mutator-libfuzzer.a
|
||||
# protobuf-mutator.a
|
||||
# protobuf.a
|
||||
# )
|
||||
# set_target_properties(yul_proto_diff_custom_mutate_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
|
||||
|
||||
add_executable(abiv2_proto_ossfuzz
|
||||
../../EVMHost.cpp
|
||||
abiV2ProtoFuzzer.cpp
|
||||
@ -78,6 +97,24 @@ if (OSSFUZZ)
|
||||
protobuf.a
|
||||
)
|
||||
set_target_properties(abiv2_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
|
||||
|
||||
add_executable(sol_proto_ossfuzz
|
||||
solProtoFuzzer.cpp
|
||||
../fuzzer_common.cpp
|
||||
protoToSol.cpp
|
||||
solProto.pb.cc
|
||||
abiV2Proto.pb.cc
|
||||
protoToAbiV2.cpp
|
||||
)
|
||||
target_include_directories(sol_proto_ossfuzz PRIVATE
|
||||
/usr/include/libprotobuf-mutator
|
||||
)
|
||||
target_link_libraries(sol_proto_ossfuzz PRIVATE solidity libsolc
|
||||
protobuf-mutator-libfuzzer.a
|
||||
protobuf-mutator.a
|
||||
protobuf.a
|
||||
)
|
||||
set_target_properties(sol_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
|
||||
else()
|
||||
add_library(solc_opt_ossfuzz
|
||||
solc_opt_ossfuzz.cpp
|
||||
|
@ -704,7 +704,7 @@ void TypeVisitor::structDefinition(StructType const& _type)
|
||||
// Commence struct declaration
|
||||
string structDef = lineString(
|
||||
"struct " +
|
||||
string(s_structNamePrefix) +
|
||||
m_structPrefix +
|
||||
to_string(m_structCounter) +
|
||||
" {"
|
||||
);
|
||||
@ -718,7 +718,7 @@ void TypeVisitor::structDefinition(StructType const& _type)
|
||||
if (!ValidityVisitor().visit(t))
|
||||
continue;
|
||||
|
||||
TypeVisitor tVisitor(m_structCounter + 1);
|
||||
TypeVisitor tVisitor(m_structCounter + 1, m_indentation - 1, m_structPrefix);
|
||||
type = tVisitor.visit(t);
|
||||
m_structCounter += tVisitor.numStructs();
|
||||
m_structDef << tVisitor.structDef();
|
||||
@ -749,7 +749,7 @@ string TypeVisitor::visit(StructType const& _type)
|
||||
// Set last dyn param if struct contains a dyn param e.g., bytes, array etc.
|
||||
m_isLastDynParamRightPadded = DynParamVisitor().visit(_type);
|
||||
// If top-level struct is a non-emtpy struct, assign the name S<suffix>
|
||||
m_baseType = s_structTypeName + to_string(m_structStartCounter);
|
||||
m_baseType = m_structPrefix + to_string(m_structStartCounter);
|
||||
}
|
||||
else
|
||||
m_baseType = {};
|
||||
|
@ -152,7 +152,7 @@ public:
|
||||
ProtoConverter(ProtoConverter const&) = delete;
|
||||
ProtoConverter(ProtoConverter&&) = delete;
|
||||
std::string contractToString(Contract const& _input);
|
||||
private:
|
||||
|
||||
enum class Delimiter
|
||||
{
|
||||
ADD,
|
||||
@ -205,7 +205,7 @@ private:
|
||||
/// Solidity code to be placed inside test function scope.
|
||||
template <typename T>
|
||||
std::pair<std::string, std::string> processType(T const& _type, bool _isValueType);
|
||||
|
||||
private:
|
||||
/// Convert a protobuf type @a _T into Solidity variable assignment and check
|
||||
/// statements to be placed inside contract and test function scopes.
|
||||
/// @param: _varName is the name of the Solidity variable
|
||||
@ -348,6 +348,8 @@ private:
|
||||
return s_paramNamePrefix;
|
||||
case Contract_Test::Contract_Test_RETURNDATA_CODER:
|
||||
return s_localVarNamePrefix;
|
||||
default:
|
||||
return s_localVarNamePrefix;
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,6 +377,7 @@ private:
|
||||
std::ostringstream m_typedReturn;
|
||||
/// Argument names to be passed to coder functions
|
||||
std::ostringstream m_argsCoder;
|
||||
public:
|
||||
/// Predicate that is true if we are in contract scope
|
||||
bool m_isStateVar;
|
||||
unsigned m_counter;
|
||||
@ -588,12 +591,13 @@ private:
|
||||
class TypeVisitor: public AbiV2ProtoVisitor<std::string>
|
||||
{
|
||||
public:
|
||||
TypeVisitor(unsigned _structSuffix = 0):
|
||||
m_indentation(1),
|
||||
TypeVisitor(unsigned _structSuffix = 0, unsigned _indentation = 1, std::string _structPrefix = "S"):
|
||||
m_indentation(_indentation),
|
||||
m_structCounter(_structSuffix),
|
||||
m_structStartCounter(_structSuffix),
|
||||
m_structFieldCounter(0),
|
||||
m_isLastDynParamRightPadded(false)
|
||||
m_isLastDynParamRightPadded(false),
|
||||
m_structPrefix(_structPrefix)
|
||||
{}
|
||||
|
||||
std::string visit(BoolType const&) override;
|
||||
@ -649,8 +653,7 @@ private:
|
||||
unsigned m_structStartCounter;
|
||||
unsigned m_structFieldCounter;
|
||||
bool m_isLastDynParamRightPadded;
|
||||
|
||||
static auto constexpr s_structTypeName = "S";
|
||||
std::string m_structPrefix;
|
||||
};
|
||||
|
||||
/// Returns a pair of strings, first of which contains assignment statements
|
||||
|
803
test/tools/ossfuzz/protoToSol.cpp
Normal file
803
test/tools/ossfuzz/protoToSol.cpp
Normal file
@ -0,0 +1,803 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
#include "protoToSol.h"
|
||||
#include "protoToAbiV2.h"
|
||||
|
||||
#include <libsolutil/Whiskers.h>
|
||||
|
||||
using namespace solidity::test::solprotofuzzer;
|
||||
using namespace std;
|
||||
using namespace solidity::util;
|
||||
|
||||
string ProtoConverter::protoToSolidity(Program const& _p)
|
||||
{
|
||||
return visit(_p);
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Program const& _p)
|
||||
{
|
||||
ostringstream program;
|
||||
ostringstream contracts;
|
||||
|
||||
for (auto &contract: _p.contracts())
|
||||
contracts << visit(contract);
|
||||
|
||||
program << Whiskers(R"(
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
pragma experimental SMTChecker;
|
||||
|
||||
<contracts>
|
||||
)")
|
||||
("contracts", contracts.str())
|
||||
.render();
|
||||
return program.str();
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(ContractType const& _contractType)
|
||||
{
|
||||
switch (_contractType.contract_type_oneof_case())
|
||||
{
|
||||
case ContractType::kC:
|
||||
return visit(_contractType.c());
|
||||
case ContractType::kL:
|
||||
return visit(_contractType.l());
|
||||
case ContractType::kI:
|
||||
return visit(_contractType.i());
|
||||
case ContractType::CONTRACT_TYPE_ONEOF_NOT_SET:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(ContractOrInterface const& _contractOrInterface)
|
||||
{
|
||||
switch (_contractOrInterface.contract_or_interface_oneof_case())
|
||||
{
|
||||
case ContractOrInterface::kC:
|
||||
return visit(_contractOrInterface.c());
|
||||
case ContractOrInterface::kI:
|
||||
return visit(_contractOrInterface.i());
|
||||
case ContractOrInterface::CONTRACT_OR_INTERFACE_ONEOF_NOT_SET:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::traverseOverrides(Interface const& _interface, bool _isOverride, bool _implement, bool _inheritedByContract, bool _isVirtual)
|
||||
{
|
||||
ostringstream funcs;
|
||||
|
||||
for (auto ancestor = _interface.ancestors().rbegin(); ancestor != _interface.ancestors().rend(); ancestor++)
|
||||
{
|
||||
unsigned index = 0;
|
||||
m_numContracts++;
|
||||
|
||||
m_numStructs = 0;
|
||||
|
||||
for (auto& f: ancestor->funcdef())
|
||||
{
|
||||
string funcStr = visit(
|
||||
f,
|
||||
index++,
|
||||
true,
|
||||
m_interfaceNameMap[&*ancestor],
|
||||
_implement,
|
||||
_inheritedByContract,
|
||||
_isVirtual
|
||||
);
|
||||
|
||||
if (f.override() || _isOverride)
|
||||
funcs << funcStr;
|
||||
}
|
||||
funcs << traverseOverrides(*ancestor, _isOverride, _implement, _inheritedByContract, _isVirtual);
|
||||
}
|
||||
return funcs.str();
|
||||
}
|
||||
|
||||
string ProtoConverter::traverseOverrides(Contract const& _contract, bool _isAbstract)
|
||||
{
|
||||
ostringstream funcs;
|
||||
bool isImplemented = m_isImplemented;
|
||||
|
||||
for (auto ancestor = _contract.ancestors().rbegin(); ancestor != _contract.ancestors().rend(); ancestor++)
|
||||
{
|
||||
if (ancestor->contract_or_interface_oneof_case() == ContractOrInterface::CONTRACT_OR_INTERFACE_ONEOF_NOT_SET)
|
||||
continue;
|
||||
|
||||
m_numContracts++;
|
||||
m_numStructs = 0;
|
||||
|
||||
if (ancestor->has_c())
|
||||
{
|
||||
unsigned index = 0;
|
||||
if (_contract.abstract() && !ancestor->c().abstract())
|
||||
m_isImplemented = true;
|
||||
|
||||
for (auto& f: ancestor->c().funcdef())
|
||||
{
|
||||
string funcStr = visit(
|
||||
f,
|
||||
index++,
|
||||
true,
|
||||
_isAbstract,
|
||||
f.virtualfunc() || !f.implemented(),
|
||||
m_isImplemented,
|
||||
m_contractNameMap[&ancestor->c()]
|
||||
);
|
||||
if ((f.virtualfunc() && !f.implemented() && !_isAbstract) ||
|
||||
(f.virtualfunc() && f.override()) ||
|
||||
(ancestor->c().abstract() && !f.implemented()))
|
||||
funcs << funcStr;
|
||||
}
|
||||
funcs << traverseOverrides(ancestor->c(), _isAbstract);
|
||||
}
|
||||
else if (ancestor->has_i())
|
||||
{
|
||||
unsigned index = 0;
|
||||
for (auto& f: ancestor->i().funcdef())
|
||||
funcs << visit(
|
||||
f,
|
||||
index++,
|
||||
true,
|
||||
m_interfaceNameMap[&ancestor->i()],
|
||||
true,
|
||||
true,
|
||||
true
|
||||
);
|
||||
funcs << traverseOverrides(ancestor->i(), true, true, true, true);
|
||||
}
|
||||
}
|
||||
m_isImplemented = isImplemented;
|
||||
return funcs.str();
|
||||
}
|
||||
|
||||
tuple<string, string, string> ProtoConverter::visitContractHelper(CI _cOrI, string _programName)
|
||||
{
|
||||
ostringstream ancestors;
|
||||
ostringstream funcs;
|
||||
ostringstream ancestorNames;
|
||||
|
||||
string separator{};
|
||||
if (holds_alternative<Interface const*>(_cOrI))
|
||||
{
|
||||
auto interface = get<Interface const*>(_cOrI);
|
||||
for (auto &ancestor: interface->ancestors())
|
||||
{
|
||||
string ancestorStr = visit(ancestor);
|
||||
if (ancestorStr.empty())
|
||||
continue;
|
||||
ancestors << ancestorStr;
|
||||
ancestorNames << separator
|
||||
<< m_interfaceNameMap[&ancestor];
|
||||
if (separator.empty())
|
||||
separator = ", ";
|
||||
}
|
||||
|
||||
unsigned wasNumContract = m_numContracts;
|
||||
|
||||
// First define overridden functions
|
||||
bool overrides = interface->ancestors_size() > 0 && !ancestorNames.str().empty();
|
||||
if (overrides)
|
||||
{
|
||||
funcs << traverseOverrides(*interface, false, false, false, false);
|
||||
}
|
||||
|
||||
m_numContracts = wasNumContract;
|
||||
m_numStructs = 0;
|
||||
|
||||
unsigned index = 0;
|
||||
// Define non-overridden functions
|
||||
for (auto &f: interface->funcdef())
|
||||
funcs << visit(f, index++, false, _programName);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto contract = get<Contract const*>(_cOrI);
|
||||
|
||||
for (auto &ancestor: contract->ancestors())
|
||||
{
|
||||
string ancestorStr = visit(ancestor);
|
||||
if (ancestorStr.empty())
|
||||
continue;
|
||||
ancestors << ancestorStr;
|
||||
ancestorNames << separator
|
||||
<< (ancestor.has_c() ? m_contractNameMap[&ancestor.c()] : m_interfaceNameMap[&ancestor.i()]);
|
||||
if (separator.empty())
|
||||
separator = ", ";
|
||||
}
|
||||
|
||||
unsigned wasNumContract = m_numContracts;
|
||||
|
||||
// First define overridden functions
|
||||
bool overrides = contract->ancestors_size() > 0 && !ancestorNames.str().empty();
|
||||
if (overrides)
|
||||
{
|
||||
funcs << traverseOverrides(*contract, contract->abstract());
|
||||
}
|
||||
|
||||
m_numContracts = wasNumContract;
|
||||
m_numStructs = 0;
|
||||
|
||||
// Define non-overridden functions
|
||||
unsigned index = 0;
|
||||
for (auto &f: contract->funcdef())
|
||||
funcs << visit(
|
||||
f,
|
||||
index++,
|
||||
false,
|
||||
contract->abstract(),
|
||||
(f.virtualfunc() || (contract->abstract() && !f.implemented())),
|
||||
false,
|
||||
_programName
|
||||
);
|
||||
}
|
||||
return make_tuple(ancestors.str(), ancestorNames.str(), funcs.str());
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Interface const& _interface)
|
||||
{
|
||||
string programName{"I" + to_string(m_numContracts++)};
|
||||
m_interfaceNameMap.insert(pair(&_interface, programName));
|
||||
m_numStructs = 0;
|
||||
auto [ancestors, ancestorNames, funcs] = visitContractHelper(&_interface, programName);
|
||||
return Whiskers(R"(
|
||||
<ancestors>
|
||||
<programType> <programName><?inheritance> is <ancestorNames></inheritance> {
|
||||
<functionDefs>
|
||||
})")
|
||||
("ancestors", ancestors)
|
||||
("programType", "interface")
|
||||
("programName", programName)
|
||||
("inheritance", _interface.ancestors_size() > 0 && !ancestorNames.empty())
|
||||
("ancestorNames", ancestorNames)
|
||||
("functionDefs", funcs)
|
||||
.render();
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Library const& _library)
|
||||
{
|
||||
ostringstream funcs;
|
||||
string programName{"L" + to_string(m_numContracts++)};
|
||||
|
||||
unsigned index = 0;
|
||||
m_numStructs = 0;
|
||||
for (auto &f: _library.funcdef())
|
||||
funcs << visit(f, index++, programName);
|
||||
|
||||
return Whiskers(R"(
|
||||
library <programName> {
|
||||
<functionDefs>
|
||||
})")
|
||||
("programName", programName)
|
||||
("functionDefs", funcs.str())
|
||||
.render();
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Contract const& _contract)
|
||||
{
|
||||
string programName{"C" + to_string(m_numContracts++)};
|
||||
m_contractNameMap.insert(pair(&_contract, programName));
|
||||
m_numStructs = 0;
|
||||
auto [ancestors, ancestorNames, funcs] = visitContractHelper(&_contract, programName);
|
||||
return Whiskers(R"(
|
||||
<ancestors>
|
||||
<?isAbstract>abstract </isAbstract><programType> <programName><?inheritance> is <ancestorNames></inheritance> {
|
||||
<functionDefs>
|
||||
})")
|
||||
("ancestors", ancestors)
|
||||
("isAbstract", _contract.abstract())
|
||||
("programType", "contract")
|
||||
("programName", programName)
|
||||
("inheritance", _contract.ancestors_size() > 0 && !ancestorNames.empty())
|
||||
("ancestorNames", ancestorNames)
|
||||
("functionDefs", funcs)
|
||||
.render();
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Modifier const& _mod)
|
||||
{
|
||||
return Whiskers(R"(
|
||||
modifier m<i>(<?isParams><params></isParams>) {
|
||||
<body>
|
||||
_;
|
||||
})")
|
||||
("i", to_string(m_numMods++))
|
||||
("isParams", _mod.params_size() > 0)
|
||||
("params", "")
|
||||
("body", "")
|
||||
.render();
|
||||
}
|
||||
|
||||
tuple<string, string, string> ProtoConverter::visit(
|
||||
FunctionParamsAndReturns const& _pr,
|
||||
bool _isExternal,
|
||||
string _programName
|
||||
)
|
||||
{
|
||||
string paramsString;
|
||||
string typeDefsParamsString;
|
||||
unsigned structsAdded = 0;
|
||||
unsigned index = 0;
|
||||
string separator{};
|
||||
string structPrefix = _programName + "S";
|
||||
|
||||
for (auto ¶m: _pr.params())
|
||||
{
|
||||
solidity::test::abiv2fuzzer::TypeVisitor typeVisitor(m_numStructs, 2, structPrefix);
|
||||
typeVisitor.visit(param);
|
||||
if (!typeVisitor.baseType().empty())
|
||||
{
|
||||
paramsString += Whiskers(
|
||||
R"(<sep><type><?isNonValue> <?isExternal>calldata<!isExternal>memory</isExternal></isNonValue> p<i>)")
|
||||
("type", typeVisitor.baseType())
|
||||
("isNonValue", param.type_oneof_case() == param.kNvtype)
|
||||
("isExternal", _isExternal)
|
||||
("i", to_string(index++))
|
||||
("sep", separator)
|
||||
.render();
|
||||
typeDefsParamsString += typeVisitor.structDef();
|
||||
m_numStructs += typeVisitor.numStructs();
|
||||
structsAdded += typeVisitor.numStructs();
|
||||
if (separator.empty())
|
||||
separator = ", ";
|
||||
}
|
||||
}
|
||||
|
||||
separator = "";
|
||||
string returnString;
|
||||
string typeDefsReturnsString;
|
||||
for (auto &ret: _pr.returns())
|
||||
{
|
||||
solidity::test::abiv2fuzzer::TypeVisitor typeVisitor(m_numStructs, 2, structPrefix);
|
||||
typeVisitor.visit(ret);
|
||||
if (!typeVisitor.baseType().empty())
|
||||
{
|
||||
returnString += Whiskers(R"(<sep><type><?isNonValue> memory</isNonValue>)")
|
||||
("type", typeVisitor.baseType())
|
||||
("isNonValue", ret.type_oneof_case() == ret.kNvtype)
|
||||
("sep", separator)
|
||||
.render();
|
||||
typeDefsReturnsString += typeVisitor.structDef();
|
||||
m_numStructs += typeVisitor.numStructs();
|
||||
structsAdded += typeVisitor.numStructs();
|
||||
if (separator.empty())
|
||||
separator = ", ";
|
||||
}
|
||||
}
|
||||
return make_tuple(typeDefsParamsString + typeDefsReturnsString, paramsString, returnString);
|
||||
}
|
||||
|
||||
bool ProtoConverter::disallowedContractFunction(ContractFunction const& _contractFunction, bool _isVirtual)
|
||||
{
|
||||
// Private virtual functions are disallowed
|
||||
if (functionVisibility(_contractFunction.vis()) == "private" && _isVirtual)
|
||||
return true;
|
||||
// Private payable functions are disallowed
|
||||
else if (functionVisibility(_contractFunction.vis()) == "private" && stateMutability(_contractFunction.mut()) == "payable")
|
||||
return true;
|
||||
// Internal payable functions are disallowed
|
||||
else if (functionVisibility(_contractFunction.vis()) == "internal" && stateMutability(_contractFunction.mut()) == "payable")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(
|
||||
ContractFunction const& _contractFunction,
|
||||
unsigned _index,
|
||||
bool _isOverride,
|
||||
bool _isAbstractContract,
|
||||
bool _isVirtual,
|
||||
bool _isImplemented,
|
||||
string _programName
|
||||
)
|
||||
{
|
||||
if (disallowedContractFunction(_contractFunction, _isVirtual || _contractFunction.virtualfunc()))
|
||||
return "";
|
||||
|
||||
auto [structDefString, paramString, returnString] = visit(
|
||||
_contractFunction.paramandret(),
|
||||
_contractFunction.vis() == ContractFunction_Visibility_EXTERNAL,
|
||||
_programName
|
||||
);
|
||||
|
||||
bool isUnimplemented = _isAbstractContract && !_contractFunction.implemented() && !_isImplemented;
|
||||
|
||||
return Whiskers(R"(
|
||||
<?isTypeDefs><typeDefs></isTypeDefs>
|
||||
|
||||
function <functionPrefix><i>(<?isParams><params></isParams>)<?isOverride> override</isOverride><?isVirtual> virtual</isVirtual> <visibility> <stateMutability><?isMod> <modifier></isMod><?isReturn> returns (<types>)</isReturn><?isUnimplemented>;<!isUnimplemented>
|
||||
{
|
||||
<body>
|
||||
}
|
||||
</isUnimplemented>
|
||||
<?isMod>
|
||||
<modifierDef>
|
||||
</isMod>)")
|
||||
("isTypeDefs", !_isOverride)
|
||||
("typeDefs", structDefString)
|
||||
("functionPrefix", boost::algorithm::to_lower_copy(_programName) + s_functionPrefix)
|
||||
("i", to_string(_index))
|
||||
("isParams", _contractFunction.paramandret().params_size() > 0 && !paramString.empty())
|
||||
("params", paramString)
|
||||
("isVirtual", _isVirtual)
|
||||
("isOverride", _isOverride)
|
||||
("visibility", functionVisibility(_contractFunction.vis()))
|
||||
("stateMutability", stateMutability(_contractFunction.mut()))
|
||||
("isMod", _contractFunction.has_m() && !isUnimplemented)
|
||||
("modifier", "m" + to_string(m_numMods))
|
||||
("isReturn", _contractFunction.paramandret().returns_size() > 0 && !returnString.empty())
|
||||
("types", returnString)
|
||||
("body", "")
|
||||
("isUnimplemented", isUnimplemented)
|
||||
("modifierDef", visit(_contractFunction.m()))
|
||||
.render();
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(LibraryFunction const& _libraryFunction, unsigned _index, string _programName)
|
||||
{
|
||||
auto [typeDefs, params, returns] = visit(
|
||||
_libraryFunction.paramandret(),
|
||||
_libraryFunction.vis() == LibraryFunction_Visibility_EXTERNAL,
|
||||
_programName
|
||||
);
|
||||
|
||||
return Whiskers(R"(
|
||||
<typeDefs>
|
||||
|
||||
function <functionPrefix><functionSuffix>(<?isParams><params></isParams>) <visibility> <stateMutability><?isMod> <modifier></isMod><?isReturn> returns (<types>)</isReturn>
|
||||
{
|
||||
<body>
|
||||
}
|
||||
|
||||
<?isMod>
|
||||
<modifierDef>
|
||||
</isMod>)")
|
||||
("typeDefs", typeDefs)
|
||||
("functionPrefix", s_libraryFunctionPrefix)
|
||||
("functionSuffix", to_string(_index))
|
||||
("isParams", _libraryFunction.paramandret().params_size() > 0 && !params.empty())
|
||||
("params", params)
|
||||
("visibility", functionVisibility(_libraryFunction.vis()))
|
||||
("stateMutability", stateMutability(_libraryFunction.mut()))
|
||||
("isMod", _libraryFunction.has_m())
|
||||
("modifier", "m" + to_string(m_numMods))
|
||||
("isReturn", _libraryFunction.paramandret().returns_size() > 0 && !returns.empty())
|
||||
("types", returns)
|
||||
("body", "")
|
||||
("modifierDef", visit(_libraryFunction.m()))
|
||||
.render();
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(
|
||||
InterfaceFunction const& _interfaceFunction,
|
||||
unsigned _index,
|
||||
bool _isOverride,
|
||||
string _programName,
|
||||
bool _implement,
|
||||
bool _inheritedByContract,
|
||||
bool _isVirtual
|
||||
)
|
||||
{
|
||||
auto [typeDefs, params, returns] = visit(
|
||||
_interfaceFunction.paramandret(),
|
||||
true,
|
||||
_programName
|
||||
);
|
||||
|
||||
return Whiskers(R"(
|
||||
<?isTypeDefs><typeDefs></isTypeDefs>
|
||||
|
||||
function <functionPrefix><functionSuffix>(<?isParams><params></isParams>) external <stateMutability><?isOverride> override</isOverride><?isVirtual> virtual</isVirtual><?isReturn> returns (<types>)</isReturn><?isImplemented> <block><!isImplemented><?inheritedByContract> virtual;<!inheritedByContract>;</inheritedByContract></isImplemented>
|
||||
)")
|
||||
("isTypeDefs", !_isOverride)
|
||||
("typeDefs", typeDefs)
|
||||
("functionPrefix", boost::algorithm::to_lower_copy(_programName) + s_functionPrefix)
|
||||
("functionSuffix", to_string(_index))
|
||||
("isParams", _interfaceFunction.paramandret().params_size() > 0 && !params.empty())
|
||||
("params", params)
|
||||
("stateMutability", stateMutability(_interfaceFunction.mut()))
|
||||
("isOverride", _isOverride)
|
||||
("isVirtual", _isVirtual)
|
||||
("isReturn", _interfaceFunction.paramandret().returns_size() > 0 && !returns.empty())
|
||||
("types", returns)
|
||||
("isImplemented", _implement)
|
||||
("inheritedByContract", _inheritedByContract)
|
||||
("block", "{}")
|
||||
.render();
|
||||
}
|
||||
|
||||
pair<string, string> ProtoConverter::visit(Block const& _block)
|
||||
{
|
||||
pair<string, string> block;
|
||||
for (auto &statement: _block.statements())
|
||||
{
|
||||
block.first += visit(statement).first;
|
||||
block.second += visit(statement).second;
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
pair<string, string> ProtoConverter::visit(Statement const& _stmt)
|
||||
{
|
||||
switch (_stmt.stmt_oneof_case())
|
||||
{
|
||||
case Statement::kVar:
|
||||
return visit(_stmt.var(), false);
|
||||
case Statement::kIfstmt:
|
||||
return visit(_stmt.ifstmt());
|
||||
case Statement::kForstmt:
|
||||
return make_pair("", visit(_stmt.forstmt()));
|
||||
case Statement::kSwitchstmt:
|
||||
return make_pair("", visit(_stmt.switchstmt()));
|
||||
case Statement::kBreakstmt:
|
||||
return make_pair("", visit(_stmt.breakstmt()));
|
||||
case Statement::kContinuestmt:
|
||||
return make_pair("", visit(_stmt.continuestmt()));
|
||||
case Statement::kReturnstmt:
|
||||
return make_pair("", visit(_stmt.returnstmt()));
|
||||
case Statement::kDostmt:
|
||||
return visit(_stmt.dostmt());
|
||||
case Statement::kWhilestmt:
|
||||
return visit(_stmt.whilestmt());
|
||||
case Statement::STMT_ONEOF_NOT_SET:
|
||||
return make_pair("", "");
|
||||
}
|
||||
}
|
||||
|
||||
pair<string, string> ProtoConverter::visit(solidity::test::abiv2fuzzer::VarDecl const& _varDecl, bool _stateVar)
|
||||
{
|
||||
solidity::test::abiv2fuzzer::ProtoConverter converter;
|
||||
converter.m_isStateVar = _stateVar;
|
||||
converter.m_varCounter = m_numVars;
|
||||
converter.m_structCounter = m_numStructs;
|
||||
auto decl = converter.visit(_varDecl);
|
||||
if (!decl.first.empty())
|
||||
{
|
||||
m_numVars++;
|
||||
m_numStructs += converter.m_numStructsAdded;
|
||||
decl.second += "\n" +
|
||||
solidity::test::abiv2fuzzer::AssignCheckVisitor{
|
||||
solidity::test::abiv2fuzzer::ProtoConverter::s_stateVarNamePrefix +
|
||||
to_string(m_numVars - 1),
|
||||
"",
|
||||
0,
|
||||
"true",
|
||||
0,
|
||||
m_numStructs - 1
|
||||
}.visit(_varDecl.type()).second;
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
|
||||
pair<string, string> ProtoConverter::visit(IfStmt const& _ifstmt)
|
||||
{
|
||||
string ifCond = visit(_ifstmt.condition());
|
||||
pair<string, string> buffer = visit(_ifstmt.statements());
|
||||
|
||||
return make_pair(buffer.first, Whiskers(R"(if (<cond>) {
|
||||
<statements>
|
||||
}
|
||||
)")
|
||||
("cond", ifCond)
|
||||
("statements", buffer.second)
|
||||
.render());
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(ForStmt const&)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(SwitchStmt const&)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(BreakStmt const&)
|
||||
{
|
||||
return "break;\n";
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(ContinueStmt const&)
|
||||
{
|
||||
return "continue;\n";
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(ReturnStmt const& _returnstmt)
|
||||
{
|
||||
return Whiskers(R"(return <expr>;
|
||||
)")
|
||||
("expr", visit(_returnstmt.value()))
|
||||
.render();
|
||||
}
|
||||
|
||||
pair<string, string> ProtoConverter::visit(DoStmt const& _dostmt)
|
||||
{
|
||||
string doCond = visit(_dostmt.condition());
|
||||
pair<string, string> buffer = visit(_dostmt.statements());
|
||||
|
||||
return make_pair(buffer.first, Whiskers(R"(do {
|
||||
<statements>
|
||||
} while (<cond>)
|
||||
)")
|
||||
("cond", doCond)
|
||||
("statements", buffer.second)
|
||||
.render());
|
||||
}
|
||||
|
||||
pair<string, string> ProtoConverter::visit(WhileStmt const& _whilestmt)
|
||||
{
|
||||
string whileCond = visit(_whilestmt.condition());
|
||||
pair<string, string> buffer = visit(_whilestmt.statements());
|
||||
|
||||
return make_pair(buffer.first, Whiskers(R"(while (<cond>) {
|
||||
<statements>
|
||||
}
|
||||
)")
|
||||
("cond", whileCond)
|
||||
("statements", buffer.second)
|
||||
.render());
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Expression const& _expr)
|
||||
{
|
||||
switch (_expr.expr_oneof_case())
|
||||
{
|
||||
case Expression::kLit:
|
||||
return visit(_expr.lit());
|
||||
case Expression::kBop:
|
||||
return visit(_expr.bop());
|
||||
case Expression::kUop:
|
||||
return visit(_expr.uop());
|
||||
case Expression::kRef:
|
||||
return visit(_expr.ref());
|
||||
case Expression::EXPR_ONEOF_NOT_SET:
|
||||
return "\"\"";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Literal const& _literal)
|
||||
{
|
||||
switch (_literal.literal_oneof_case())
|
||||
{
|
||||
case Literal::kBlit:
|
||||
return _literal.blit() ? "true" : "false";
|
||||
case Literal::kSlit:
|
||||
return "\"" + _literal.slit() + "\"";
|
||||
case Literal::LITERAL_ONEOF_NOT_SET:
|
||||
return "\"\"";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(BinaryOp const& _bop)
|
||||
{
|
||||
string op;
|
||||
switch (_bop.op())
|
||||
{
|
||||
case BinaryOp_Operation_ADD:
|
||||
op = "+";
|
||||
break;
|
||||
case BinaryOp_Operation_SUB:
|
||||
op = "-";
|
||||
break;
|
||||
case BinaryOp_Operation_MUL:
|
||||
op = "*";
|
||||
break;
|
||||
case BinaryOp_Operation_DIV:
|
||||
op = "/";
|
||||
break;
|
||||
}
|
||||
return Whiskers(R"(<arg1> <op> <arg2>)")
|
||||
("arg1", visit(_bop.arg1()))
|
||||
("op", op)
|
||||
("arg2", visit(_bop.arg2()))
|
||||
.render();
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(UnaryOp const& _uop)
|
||||
{
|
||||
string op;
|
||||
switch (_uop.op())
|
||||
{
|
||||
case UnaryOp_Operation_INC:
|
||||
op = "++";
|
||||
break;
|
||||
case UnaryOp_Operation_DEC:
|
||||
op = "--";
|
||||
break;
|
||||
}
|
||||
return Whiskers(R"(<arg><op>)")
|
||||
("arg", visit(_uop.arg()))
|
||||
("op", op)
|
||||
.render();
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(VarRef const& _varref)
|
||||
{
|
||||
if (m_numVars > 0)
|
||||
return solidity::test::abiv2fuzzer::ProtoConverter::s_stateVarNamePrefix + to_string(_varref.varnum() % m_numVars);
|
||||
else
|
||||
return "\"\"";
|
||||
}
|
||||
|
||||
string ProtoConverter::functionVisibility(ContractFunction::Visibility _vis)
|
||||
{
|
||||
switch (_vis)
|
||||
{
|
||||
case ContractFunction_Visibility_PUBLIC:
|
||||
return "public";
|
||||
case ContractFunction_Visibility_PRIVATE:
|
||||
return "private";
|
||||
case ContractFunction_Visibility_EXTERNAL:
|
||||
return "external";
|
||||
case ContractFunction_Visibility_INTERNAL:
|
||||
return "internal";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::functionVisibility(LibraryFunction::Visibility _vis)
|
||||
{
|
||||
switch (_vis)
|
||||
{
|
||||
case LibraryFunction_Visibility_PUBLIC:
|
||||
return "public";
|
||||
case LibraryFunction_Visibility_PRIVATE:
|
||||
return "private";
|
||||
case LibraryFunction_Visibility_EXTERNAL:
|
||||
return "external";
|
||||
case LibraryFunction_Visibility_INTERNAL:
|
||||
return "internal";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::stateMutability(ContractFunction::StateMutability _mut)
|
||||
{
|
||||
switch (_mut)
|
||||
{
|
||||
case ContractFunction_StateMutability_PURE:
|
||||
return "pure";
|
||||
case ContractFunction_StateMutability_VIEW:
|
||||
return "view";
|
||||
case ContractFunction_StateMutability_PAYABLE:
|
||||
return "payable";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::stateMutability(LibraryFunction::StateMutability _mut)
|
||||
{
|
||||
switch (_mut)
|
||||
{
|
||||
case LibraryFunction_StateMutability_PURE:
|
||||
return "pure";
|
||||
case LibraryFunction_StateMutability_VIEW:
|
||||
return "view";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::stateMutability(InterfaceFunction::StateMutability _mut)
|
||||
{
|
||||
switch (_mut)
|
||||
{
|
||||
case InterfaceFunction_StateMutability_PURE:
|
||||
return "pure";
|
||||
case InterfaceFunction_StateMutability_VIEW:
|
||||
return "view";
|
||||
case InterfaceFunction_StateMutability_PAYABLE:
|
||||
return "payable";
|
||||
}
|
||||
}
|
150
test/tools/ossfuzz/protoToSol.h
Normal file
150
test/tools/ossfuzz/protoToSol.h
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <test/tools/ossfuzz/solProto.pb.h>
|
||||
#include <variant>
|
||||
|
||||
namespace solidity::test::solprotofuzzer
|
||||
{
|
||||
struct ProgramInfo
|
||||
{
|
||||
enum class ProgramType
|
||||
{
|
||||
LIBRARY,
|
||||
CONTRACT,
|
||||
INTERFACE
|
||||
};
|
||||
std::string m_name;
|
||||
std::string m_userDefinedTypes;
|
||||
ProgramType m_programType;
|
||||
};
|
||||
|
||||
struct FunctionInfo
|
||||
{
|
||||
enum class FunctionVisibility
|
||||
{
|
||||
PUBLIC,
|
||||
PRIVATE,
|
||||
INTERNAL,
|
||||
EXTERNAL
|
||||
};
|
||||
enum class StateMutability
|
||||
{
|
||||
PURE,
|
||||
VIEW,
|
||||
PAYABLE
|
||||
};
|
||||
std::string m_name;
|
||||
std::string m_params;
|
||||
std::string m_returns;
|
||||
FunctionVisibility m_visibility;
|
||||
StateMutability m_mutability;
|
||||
bool m_override;
|
||||
bool m_virtual;
|
||||
};
|
||||
|
||||
class ProtoConverter
|
||||
{
|
||||
public:
|
||||
ProtoConverter() {}
|
||||
ProtoConverter(ProtoConverter const&) = delete;
|
||||
ProtoConverter(ProtoConverter&&) = delete;
|
||||
std::string protoToSolidity(Program const&);
|
||||
private:
|
||||
using CI = std::variant<Contract const*, Interface const*>;
|
||||
|
||||
std::string visit(Program const&);
|
||||
std::string visit(ContractType const&);
|
||||
std::string visit(ContractOrInterface const&);
|
||||
std::string visit(Interface const&);
|
||||
std::string visit(Contract const&);
|
||||
std::string traverseOverrides(
|
||||
Interface const&,
|
||||
bool _isOverride,
|
||||
bool _implement,
|
||||
bool _inheritedByContract,
|
||||
bool _isVirtual
|
||||
);
|
||||
std::string traverseOverrides(
|
||||
Contract const&,
|
||||
bool _isAbstract
|
||||
);
|
||||
std::string visit(Library const&);
|
||||
std::pair<std::string, std::string> visit(Block const&);
|
||||
std::pair<std::string, std::string> visit(Statement const&);
|
||||
std::pair<std::string, std::string> visit(solidity::test::abiv2fuzzer::VarDecl const&, bool _stateVar);
|
||||
std::pair<std::string, std::string> visit(IfStmt const&);
|
||||
std::string visit(ForStmt const&);
|
||||
std::string visit(SwitchStmt const&);
|
||||
std::string visit(BreakStmt const&);
|
||||
std::string visit(ContinueStmt const&);
|
||||
std::string visit(ReturnStmt const&);
|
||||
std::pair<std::string, std::string> visit(DoStmt const&);
|
||||
std::pair<std::string, std::string> visit(WhileStmt const&);
|
||||
std::string visit(Expression const&);
|
||||
std::string visit(Literal const&);
|
||||
std::string visit(BinaryOp const&);
|
||||
std::string visit(UnaryOp const&);
|
||||
std::string visit(VarRef const&);
|
||||
std::tuple<std::string, std::string, std::string> visit(
|
||||
FunctionParamsAndReturns const& _pR,
|
||||
bool _isExternal,
|
||||
std::string _programName
|
||||
);
|
||||
std::string visit(
|
||||
InterfaceFunction const&,
|
||||
unsigned _index,
|
||||
bool _isOverride,
|
||||
std::string _programName,
|
||||
bool _implement = false,
|
||||
bool _inheritedByContract = false,
|
||||
bool _isVirtual = false
|
||||
);
|
||||
std::string visit(LibraryFunction const& _func, unsigned _index, std::string _programName);
|
||||
std::string visit(
|
||||
ContractFunction const&,
|
||||
unsigned _index,
|
||||
bool _isOverride,
|
||||
bool _isAbstractContract,
|
||||
bool _isVirtual,
|
||||
bool _isImplemented,
|
||||
std::string _programName
|
||||
);
|
||||
std::tuple<std::string, std::string, std::string> visitContractHelper(CI _cOrI, std::string _programName);
|
||||
std::string visit(Modifier const&);
|
||||
static std::string functionVisibility(ContractFunction::Visibility _vis);
|
||||
static std::string functionVisibility(LibraryFunction::Visibility _vis);
|
||||
static std::string stateMutability(ContractFunction::StateMutability _mut);
|
||||
static std::string stateMutability(LibraryFunction::StateMutability _mut);
|
||||
static std::string stateMutability(InterfaceFunction::StateMutability _mut);
|
||||
static bool disallowedContractFunction(ContractFunction const& _contractFunction, bool _isVirtual);
|
||||
|
||||
unsigned m_numVars = 0;
|
||||
unsigned m_numStructs = 0;
|
||||
unsigned m_numMods = 0;
|
||||
unsigned m_numContracts = 0;
|
||||
bool m_isImplemented = false;
|
||||
std::map<Interface const*, std::string> m_interfaceNameMap;
|
||||
std::map<Contract const*, std::string> m_contractNameMap;
|
||||
|
||||
static auto constexpr s_interfaceFunctionPrefix = "i";
|
||||
static auto constexpr s_libraryFunctionPrefix = "l";
|
||||
static auto constexpr s_contractFunctionPrefix = "c";
|
||||
static auto constexpr s_functionPrefix = "func";
|
||||
};
|
||||
}
|
228
test/tools/ossfuzz/solProto.proto
Normal file
228
test/tools/ossfuzz/solProto.proto
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
import "abiV2Proto.proto";
|
||||
|
||||
message FunctionParamsAndReturns {
|
||||
repeated solidity.test.abiv2fuzzer.Type params = 1;
|
||||
repeated solidity.test.abiv2fuzzer.Type returns = 2;
|
||||
}
|
||||
|
||||
message InterfaceFunction {
|
||||
enum StateMutability {
|
||||
PURE = 0;
|
||||
VIEW = 1;
|
||||
PAYABLE = 2;
|
||||
}
|
||||
required FunctionParamsAndReturns paramandret = 1;
|
||||
required StateMutability mut = 2;
|
||||
required bool override = 3;
|
||||
}
|
||||
|
||||
message LibraryFunction {
|
||||
// Library functions cannot be payable
|
||||
enum StateMutability {
|
||||
PURE = 0;
|
||||
VIEW = 1;
|
||||
}
|
||||
enum Visibility {
|
||||
PUBLIC = 0;
|
||||
EXTERNAL = 1;
|
||||
INTERNAL = 2;
|
||||
PRIVATE = 3;
|
||||
}
|
||||
required FunctionParamsAndReturns paramandret = 1;
|
||||
required Visibility vis = 2;
|
||||
required StateMutability mut = 3;
|
||||
required Block b = 4;
|
||||
optional Modifier m = 5;
|
||||
}
|
||||
|
||||
message ContractFunction {
|
||||
enum StateMutability {
|
||||
PURE = 0;
|
||||
VIEW = 1;
|
||||
PAYABLE = 2;
|
||||
}
|
||||
enum Visibility {
|
||||
PUBLIC = 0;
|
||||
EXTERNAL = 1;
|
||||
INTERNAL = 2;
|
||||
PRIVATE = 3;
|
||||
}
|
||||
required FunctionParamsAndReturns paramandret = 1;
|
||||
required Visibility vis = 2;
|
||||
required StateMutability mut = 3;
|
||||
required Block b = 4;
|
||||
optional Modifier m = 5;
|
||||
required bool implemented = 6;
|
||||
required bool virtualfunc = 7;
|
||||
required bool override = 8;
|
||||
}
|
||||
|
||||
message Modifier {
|
||||
repeated solidity.test.abiv2fuzzer.Type params = 1;
|
||||
required Block b = 2;
|
||||
}
|
||||
|
||||
/// Expressions
|
||||
message Expression {
|
||||
oneof expr_oneof {
|
||||
Literal lit = 1;
|
||||
BinaryOp bop = 2;
|
||||
UnaryOp uop = 3;
|
||||
VarRef ref = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message VarRef {
|
||||
required int32 varnum = 1;
|
||||
}
|
||||
|
||||
message Literal {
|
||||
oneof literal_oneof {
|
||||
bool blit = 1;
|
||||
string slit = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message BinaryOp {
|
||||
enum Operation {
|
||||
ADD = 1;
|
||||
SUB = 2;
|
||||
MUL = 3;
|
||||
DIV = 4;
|
||||
}
|
||||
required Operation op = 1;
|
||||
required Expression arg1 = 2;
|
||||
required Expression arg2 = 3;
|
||||
}
|
||||
|
||||
message UnaryOp {
|
||||
enum Operation {
|
||||
INC = 1;
|
||||
DEC = 2;
|
||||
}
|
||||
required Operation op = 1;
|
||||
required Expression arg = 2;
|
||||
}
|
||||
|
||||
/// Statements
|
||||
message ElseStmt {
|
||||
required Block statements = 1;
|
||||
}
|
||||
|
||||
message IfStmt {
|
||||
required Expression condition = 1;
|
||||
required Block statements = 2;
|
||||
optional ElseStmt else = 3;
|
||||
}
|
||||
|
||||
message ForStmt {
|
||||
required Block pre = 1;
|
||||
required Expression condition = 2;
|
||||
required Block post = 3;
|
||||
required Block body = 4;
|
||||
}
|
||||
|
||||
message CaseStmt {
|
||||
required Literal lit = 1;
|
||||
required Block block = 2;
|
||||
}
|
||||
|
||||
message SwitchStmt {
|
||||
required Expression condition = 1;
|
||||
repeated CaseStmt cases = 2;
|
||||
optional Block default = 3;
|
||||
}
|
||||
|
||||
message BreakStmt {}
|
||||
|
||||
message ContinueStmt {}
|
||||
|
||||
message ReturnStmt {
|
||||
required Expression value = 1;
|
||||
}
|
||||
|
||||
message DoStmt {
|
||||
required Expression condition = 1;
|
||||
required Block statements = 2;
|
||||
}
|
||||
|
||||
message WhileStmt {
|
||||
required Expression condition = 1;
|
||||
required Block statements = 2;
|
||||
}
|
||||
|
||||
message Statement {
|
||||
oneof stmt_oneof {
|
||||
solidity.test.abiv2fuzzer.VarDecl var = 1;
|
||||
IfStmt ifstmt = 2;
|
||||
ForStmt forstmt = 3;
|
||||
SwitchStmt switchstmt = 4;
|
||||
BreakStmt breakstmt = 5;
|
||||
ContinueStmt continuestmt = 6;
|
||||
ReturnStmt returnstmt = 7;
|
||||
DoStmt dostmt = 8;
|
||||
WhileStmt whilestmt = 9;
|
||||
}
|
||||
}
|
||||
|
||||
message Block {
|
||||
repeated Statement statements = 1;
|
||||
}
|
||||
|
||||
message Library {
|
||||
repeated solidity.test.abiv2fuzzer.VarDecl state_vars = 1;
|
||||
repeated LibraryFunction funcdef = 2;
|
||||
}
|
||||
|
||||
message Interface {
|
||||
repeated solidity.test.abiv2fuzzer.VarDecl state_vars = 1;
|
||||
repeated InterfaceFunction funcdef = 2;
|
||||
repeated Interface ancestors = 3;
|
||||
}
|
||||
|
||||
message Contract {
|
||||
repeated solidity.test.abiv2fuzzer.VarDecl state_vars = 1;
|
||||
repeated ContractFunction funcdef = 2;
|
||||
required bool abstract = 3;
|
||||
repeated ContractOrInterface ancestors = 4;
|
||||
}
|
||||
|
||||
message ContractOrInterface {
|
||||
oneof contract_or_interface_oneof {
|
||||
Contract c = 1;
|
||||
Interface i = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message ContractType {
|
||||
oneof contract_type_oneof {
|
||||
Contract c = 1;
|
||||
Library l = 2;
|
||||
Interface i = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message Program {
|
||||
repeated ContractType contracts = 1;
|
||||
}
|
||||
|
||||
package solidity.test.solprotofuzzer;
|
44
test/tools/ossfuzz/solProtoFuzzer.cpp
Normal file
44
test/tools/ossfuzz/solProtoFuzzer.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <test/tools/ossfuzz/protoToSol.h>
|
||||
#include <test/tools/ossfuzz/solProto.pb.h>
|
||||
|
||||
#include <test/tools/fuzzer_common.h>
|
||||
|
||||
#include <src/libfuzzer/libfuzzer_macro.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using namespace solidity::test::solprotofuzzer;
|
||||
using namespace std;
|
||||
|
||||
DEFINE_PROTO_FUZZER(Program const& _input)
|
||||
{
|
||||
ProtoConverter converter;
|
||||
string sol_source = converter.protoToSolidity(_input);
|
||||
|
||||
if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH"))
|
||||
{
|
||||
// With libFuzzer binary run this to generate a YUL source file x.yul:
|
||||
// PROTO_FUZZER_DUMP_PATH=x.yul ./a.out proto-input
|
||||
ofstream of(dump_path);
|
||||
of.write(sol_source.data(), sol_source.size());
|
||||
}
|
||||
FuzzerUtil::testCompiler(sol_source, /*optimize=*/false);
|
||||
return;
|
||||
}
|
Loading…
Reference in New Issue
Block a user