mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[Proto fuzzer] Add function calls, and multi variable declaration/assignment statements
This commit is contained in:
parent
c3a1c168d0
commit
495f7f9013
@ -33,7 +33,7 @@ target_link_libraries(strictasm_assembly_ossfuzz PRIVATE yul FuzzingEngine.a)
|
|||||||
|
|
||||||
add_executable(yul_proto_ossfuzz yulProtoFuzzer.cpp protoToYul.cpp yulProto.pb.cc)
|
add_executable(yul_proto_ossfuzz yulProtoFuzzer.cpp protoToYul.cpp yulProto.pb.cc)
|
||||||
target_include_directories(yul_proto_ossfuzz PRIVATE /src/libprotobuf-mutator /src/LPM/external.protobuf/include)
|
target_include_directories(yul_proto_ossfuzz PRIVATE /src/libprotobuf-mutator /src/LPM/external.protobuf/include)
|
||||||
target_link_libraries(yul_proto_ossfuzz PRIVATE yul evmasm
|
target_link_libraries(yul_proto_ossfuzz PRIVATE yul evmasm solidity
|
||||||
protobuf-mutator-libfuzzer.a
|
protobuf-mutator-libfuzzer.a
|
||||||
protobuf-mutator.a
|
protobuf-mutator.a
|
||||||
protobuf.a
|
protobuf.a
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,8 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include <test/tools/ossfuzz/yulProto.pb.h>
|
#include <test/tools/ossfuzz/yulProto.pb.h>
|
||||||
#include <libdevcore/Common.h>
|
#include <libdevcore/Common.h>
|
||||||
@ -38,31 +40,34 @@ class ProtoConverter
|
|||||||
public:
|
public:
|
||||||
ProtoConverter()
|
ProtoConverter()
|
||||||
{
|
{
|
||||||
// The hard-coded function template foo has 10 parameters that are already "live"
|
m_numLiveVars = 0;
|
||||||
m_numLiveVars = 10;
|
|
||||||
m_numVarsPerScope.push(m_numLiveVars);
|
m_numVarsPerScope.push(m_numLiveVars);
|
||||||
m_numNestedForLoops = 0;
|
m_numNestedForLoops = 0;
|
||||||
m_inForScope.push(false);
|
m_inForScope.push(false);
|
||||||
|
m_numFunctionSets = 0;
|
||||||
}
|
}
|
||||||
ProtoConverter(ProtoConverter const&) = delete;
|
ProtoConverter(ProtoConverter const&) = delete;
|
||||||
ProtoConverter(ProtoConverter&&) = delete;
|
ProtoConverter(ProtoConverter&&) = delete;
|
||||||
std::string functionToString(Function const& _input);
|
std::string programToString(Program const& _input);
|
||||||
std::string protoToYul(uint8_t const* _data, size_t _size);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void visit(BinaryOp const&);
|
void visit(BinaryOp const&);
|
||||||
void visit(Block const&);
|
void visit(Block const&);
|
||||||
|
void visit(SpecialBlock const&);
|
||||||
void visit(Literal const&);
|
void visit(Literal const&);
|
||||||
void visit(VarRef const&);
|
void visit(VarRef const&);
|
||||||
void visit(Expression const&);
|
void visit(Expression const&);
|
||||||
void visit(VarDecl const&);
|
void visit(VarDecl const&);
|
||||||
|
void visit(EmptyVarDecl const&);
|
||||||
|
void visit(MultiVarDecl const&);
|
||||||
void visit(TypedVarDecl const&);
|
void visit(TypedVarDecl const&);
|
||||||
void visit(UnaryOp const&);
|
void visit(UnaryOp const&);
|
||||||
void visit(AssignmentStatement const&);
|
void visit(AssignmentStatement const&);
|
||||||
|
void visit(MultiAssignment const&);
|
||||||
void visit(IfStmt const&);
|
void visit(IfStmt const&);
|
||||||
void visit(StoreFunc const&);
|
void visit(StoreFunc const&);
|
||||||
void visit(Statement const&);
|
void visit(Statement const&);
|
||||||
void visit(Function const&);
|
void visit(FunctionDefinition const&);
|
||||||
void visit(ForStmt const&);
|
void visit(ForStmt const&);
|
||||||
void visit(CaseStmt const&);
|
void visit(CaseStmt const&);
|
||||||
void visit(SwitchStmt const&);
|
void visit(SwitchStmt const&);
|
||||||
@ -75,19 +80,72 @@ private:
|
|||||||
void visit(RetRevStmt const&);
|
void visit(RetRevStmt const&);
|
||||||
void visit(SelfDestructStmt const&);
|
void visit(SelfDestructStmt const&);
|
||||||
void visit(TerminatingStmt const&);
|
void visit(TerminatingStmt const&);
|
||||||
|
void visit(FunctionCallNoReturnVal const&);
|
||||||
|
void visit(FunctionCallSingleReturnVal const&);
|
||||||
|
void visit(FunctionCall const&);
|
||||||
|
void visit(FunctionDefinitionNoReturnVal const&);
|
||||||
|
void visit(FunctionDefinitionSingleReturnVal const&);
|
||||||
|
void visit(FunctionDefinitionMultiReturnVal const&);
|
||||||
|
void visit(Program const&);
|
||||||
template <class T>
|
template <class T>
|
||||||
void visit(google::protobuf::RepeatedPtrField<T> const& _repeated_field);
|
void visit(google::protobuf::RepeatedPtrField<T> const& _repeated_field);
|
||||||
|
void registerFunction(FunctionDefinition const&);
|
||||||
|
|
||||||
std::string createHex(std::string const& _hexBytes) const;
|
std::string createHex(std::string const& _hexBytes) const;
|
||||||
std::string createAlphaNum(std::string const& _strBytes) const;
|
std::string createAlphaNum(std::string const& _strBytes) const;
|
||||||
bool isCaseLiteralUnique(Literal const&);
|
bool isCaseLiteralUnique(Literal const&);
|
||||||
|
enum class NumFunctionReturns
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Single,
|
||||||
|
Multiple
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void visitFunctionInputParams(T const&, unsigned);
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void createFunctionDefAndCall(T const&, unsigned, unsigned, NumFunctionReturns);
|
||||||
|
std::string functionTypeToString(NumFunctionReturns _type);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void registerFunction(T const& _x, NumFunctionReturns _type, unsigned _numOutputParams = 0)
|
||||||
|
{
|
||||||
|
unsigned numInputParams = _x.num_input_params() % modInputParams;
|
||||||
|
switch (_type)
|
||||||
|
{
|
||||||
|
case NumFunctionReturns::None:
|
||||||
|
m_functionVecNoReturnValue.push_back(numInputParams);
|
||||||
|
break;
|
||||||
|
case NumFunctionReturns::Single:
|
||||||
|
m_functionVecSingleReturnValue.push_back(numInputParams);
|
||||||
|
break;
|
||||||
|
case NumFunctionReturns::Multiple:
|
||||||
|
m_functionVecMultiReturnValue.push_back(std::make_pair(numInputParams, _numOutputParams));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::ostringstream m_output;
|
std::ostringstream m_output;
|
||||||
std::stack<uint8_t> m_numVarsPerScope;
|
// Number of live variables in inner scope of a function
|
||||||
int32_t m_numLiveVars;
|
std::stack<unsigned> m_numVarsPerScope;
|
||||||
int32_t m_numNestedForLoops;
|
// Number of live variables in function scope
|
||||||
|
unsigned m_numLiveVars;
|
||||||
|
// Number of nested for loops for loop index referencing
|
||||||
|
unsigned m_numNestedForLoops;
|
||||||
std::stack<bool> m_inForScope;
|
std::stack<bool> m_inForScope;
|
||||||
|
// Set that is used for deduplicating switch case literals
|
||||||
std::stack<std::set<dev::u256>> m_switchLiteralSetPerScope;
|
std::stack<std::set<dev::u256>> m_switchLiteralSetPerScope;
|
||||||
|
// Total number of function sets. A function set contains one function of each type defined by
|
||||||
|
// NumFunctionReturns
|
||||||
|
unsigned m_numFunctionSets;
|
||||||
|
// Look-up table per function type that holds the number of input (output) function parameters
|
||||||
|
std::vector<unsigned> m_functionVecNoReturnValue;
|
||||||
|
std::vector<unsigned> m_functionVecSingleReturnValue;
|
||||||
|
std::vector<std::pair<unsigned, unsigned>> m_functionVecMultiReturnValue;
|
||||||
|
// mod input/output parameters impose an upper bound on the number of input/output parameters a function may have.
|
||||||
|
static unsigned constexpr modInputParams = 5;
|
||||||
|
static unsigned constexpr modOutputParams = 5;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,56 @@ message VarDecl {
|
|||||||
required Expression expr = 1;
|
required Expression expr = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message FunctionCallNoReturnVal {
|
||||||
|
// Indexes a function that does not return anything
|
||||||
|
required uint32 func_index = 1;
|
||||||
|
required Expression in_param1 = 2;
|
||||||
|
required Expression in_param2 = 3;
|
||||||
|
required Expression in_param3 = 4;
|
||||||
|
required Expression in_param4 = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by Expression
|
||||||
|
message FunctionCallSingleReturnVal {
|
||||||
|
// Indexes a function that returns exactly one value
|
||||||
|
required uint32 func_index = 1;
|
||||||
|
required Expression in_param1 = 2;
|
||||||
|
required Expression in_param2 = 3;
|
||||||
|
required Expression in_param3 = 4;
|
||||||
|
required Expression in_param4 = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MultiVarDecl {
|
||||||
|
// Indexes a function that returns more than one value
|
||||||
|
required uint32 func_index = 1;
|
||||||
|
required Expression in_param1 = 2;
|
||||||
|
required Expression in_param2 = 3;
|
||||||
|
required Expression in_param3 = 4;
|
||||||
|
required Expression in_param4 = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MultiAssignment {
|
||||||
|
// Indexes a function that returns more than one value
|
||||||
|
required uint32 func_index = 1;
|
||||||
|
required Expression in_param1 = 2;
|
||||||
|
required Expression in_param2 = 3;
|
||||||
|
required Expression in_param3 = 4;
|
||||||
|
required Expression in_param4 = 5;
|
||||||
|
required VarRef out_param1 = 6;
|
||||||
|
required VarRef out_param2 = 7;
|
||||||
|
required VarRef out_param3 = 8;
|
||||||
|
required VarRef out_param4 = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We exclude function calls with single return value here and use them as expressions
|
||||||
|
message FunctionCall {
|
||||||
|
oneof functioncall_oneof {
|
||||||
|
FunctionCallNoReturnVal call_zero = 1;
|
||||||
|
MultiVarDecl call_multidecl = 2;
|
||||||
|
MultiAssignment call_multiassign = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message TypedVarDecl {
|
message TypedVarDecl {
|
||||||
enum TypeName {
|
enum TypeName {
|
||||||
BOOL = 1;
|
BOOL = 1;
|
||||||
@ -192,6 +242,7 @@ message Expression {
|
|||||||
UnaryOp unop = 4;
|
UnaryOp unop = 4;
|
||||||
TernaryOp top = 5;
|
TernaryOp top = 5;
|
||||||
NullaryOp nop = 6;
|
NullaryOp nop = 6;
|
||||||
|
FunctionCallSingleReturnVal func_expr = 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,21 +304,26 @@ message TerminatingStmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stub for a VarDecl without an Expression on the RHS
|
||||||
|
message EmptyVarDecl {}
|
||||||
|
|
||||||
|
// TODO: Make Function definition a Statement
|
||||||
message Statement {
|
message Statement {
|
||||||
oneof stmt_oneof {
|
oneof stmt_oneof {
|
||||||
VarDecl decl = 1;
|
VarDecl decl = 1;
|
||||||
AssignmentStatement assignment = 2;
|
AssignmentStatement assignment = 2;
|
||||||
IfStmt ifstmt = 3;
|
IfStmt ifstmt = 3;
|
||||||
StoreFunc storage_func = 4;
|
StoreFunc storage_func = 4;
|
||||||
Block blockstmt = 5;
|
Block blockstmt = 5;
|
||||||
ForStmt forstmt = 6;
|
ForStmt forstmt = 6;
|
||||||
SwitchStmt switchstmt = 7;
|
SwitchStmt switchstmt = 7;
|
||||||
BreakStmt breakstmt = 8;
|
BreakStmt breakstmt = 8;
|
||||||
ContinueStmt contstmt = 9;
|
ContinueStmt contstmt = 9;
|
||||||
LogFunc log_func = 10;
|
LogFunc log_func = 10;
|
||||||
CopyFunc copy_func = 11;
|
CopyFunc copy_func = 11;
|
||||||
ExtCodeCopy extcode_copy = 12;
|
ExtCodeCopy extcode_copy = 12;
|
||||||
TerminatingStmt terminatestmt = 13;
|
TerminatingStmt terminatestmt = 13;
|
||||||
|
FunctionCall functioncall = 14;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,8 +331,39 @@ message Block {
|
|||||||
repeated Statement statements = 1;
|
repeated Statement statements = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Function {
|
// Identical to Block with the addition of an empty var right at the top
|
||||||
required Block statements = 1;
|
// Used by FunctionDefinitionNoReturnVal only.
|
||||||
|
message SpecialBlock {
|
||||||
|
required EmptyVarDecl var = 1;
|
||||||
|
repeated Statement statements = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This ensures that proto mutator generates at least one of each type if it creates at least 1 functiondef message.
|
||||||
|
message FunctionDefinition {
|
||||||
|
required FunctionDefinitionNoReturnVal fd_zero = 1;
|
||||||
|
required FunctionDefinitionSingleReturnVal fd_one = 2;
|
||||||
|
required FunctionDefinitionMultiReturnVal fd_multi = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since this function can have 0 parameters, we hoist an empty var decl at the top via SpecialBlock.
|
||||||
|
message FunctionDefinitionNoReturnVal {
|
||||||
|
required uint32 num_input_params = 1;
|
||||||
|
required SpecialBlock statements = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FunctionDefinitionSingleReturnVal {
|
||||||
|
required uint32 num_input_params = 1;
|
||||||
|
required Block statements = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FunctionDefinitionMultiReturnVal {
|
||||||
|
required uint32 num_input_params = 1;
|
||||||
|
required uint32 num_output_params = 2;
|
||||||
|
required Block statements = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Program {
|
||||||
|
repeated FunctionDefinition funcs = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
package yul.test.yul_fuzzer;
|
package yul.test.yul_fuzzer;
|
||||||
|
@ -30,12 +30,10 @@ using namespace yul;
|
|||||||
using namespace yul::test::yul_fuzzer;
|
using namespace yul::test::yul_fuzzer;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
DEFINE_PROTO_FUZZER(Function const& _input)
|
DEFINE_PROTO_FUZZER(Program const& _input)
|
||||||
{
|
{
|
||||||
ProtoConverter converter;
|
ProtoConverter converter;
|
||||||
string yul_source = converter.functionToString(_input);
|
string yul_source = converter.programToString(_input);
|
||||||
if (yul_source.size() > 600)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH"))
|
if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH"))
|
||||||
{
|
{
|
||||||
@ -45,6 +43,9 @@ DEFINE_PROTO_FUZZER(Function const& _input)
|
|||||||
of.write(yul_source.data(), yul_source.size());
|
of.write(yul_source.data(), yul_source.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (yul_source.size() > 1200)
|
||||||
|
return;
|
||||||
|
|
||||||
// AssemblyStack entry point
|
// AssemblyStack entry point
|
||||||
AssemblyStack stack(
|
AssemblyStack stack(
|
||||||
langutil::EVMVersion(),
|
langutil::EVMVersion(),
|
||||||
|
@ -37,12 +37,10 @@ using namespace langutil;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace yul::test;
|
using namespace yul::test;
|
||||||
|
|
||||||
DEFINE_PROTO_FUZZER(Function const& _input)
|
DEFINE_PROTO_FUZZER(Program const& _input)
|
||||||
{
|
{
|
||||||
ProtoConverter converter;
|
ProtoConverter converter;
|
||||||
string yul_source = converter.functionToString(_input);
|
string yul_source = converter.programToString(_input);
|
||||||
if (yul_source.size() > 600)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH"))
|
if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH"))
|
||||||
{
|
{
|
||||||
@ -52,6 +50,9 @@ DEFINE_PROTO_FUZZER(Function const& _input)
|
|||||||
of.write(yul_source.data(), yul_source.size());
|
of.write(yul_source.data(), yul_source.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (yul_source.size() > 1200)
|
||||||
|
return;
|
||||||
|
|
||||||
// AssemblyStack entry point
|
// AssemblyStack entry point
|
||||||
AssemblyStack stack(
|
AssemblyStack stack(
|
||||||
langutil::EVMVersion(),
|
langutil::EVMVersion(),
|
||||||
|
Loading…
Reference in New Issue
Block a user