diff --git a/test/tools/ossfuzz/CMakeLists.txt b/test/tools/ossfuzz/CMakeLists.txt
index bed8762c2..399eada46 100644
--- a/test/tools/ossfuzz/CMakeLists.txt
+++ b/test/tools/ossfuzz/CMakeLists.txt
@@ -1,3 +1,4 @@
+link_directories(/src/LPM/src /src/LPM/src/libfuzzer /src/LPM/external.protobuf/lib)
add_custom_target(ossfuzz)
add_dependencies(ossfuzz
solc_opt_ossfuzz
@@ -6,6 +7,9 @@ add_dependencies(ossfuzz
strictasm_diff_ossfuzz
)
+add_custom_target(ossfuzz_proto)
+add_dependencies(ossfuzz_proto yul_proto_ossfuzz yul_proto_diff_ossfuzz)
+
#[[FuzzingEngine.a is provided by oss-fuzz's Dockerized build environment]]
add_executable(solc_opt_ossfuzz solc_opt_ossfuzz.cpp ../fuzzer_common.cpp)
target_link_libraries(solc_opt_ossfuzz PRIVATE libsolc evmasm FuzzingEngine.a)
@@ -17,4 +21,21 @@ add_executable(const_opt_ossfuzz const_opt_ossfuzz.cpp ../fuzzer_common.cpp)
target_link_libraries(const_opt_ossfuzz PRIVATE libsolc evmasm FuzzingEngine.a)
add_executable(strictasm_diff_ossfuzz strictasm_diff_ossfuzz.cpp yulFuzzerCommon.cpp)
-target_link_libraries(strictasm_diff_ossfuzz PRIVATE libsolc evmasm yulInterpreter FuzzingEngine.a)
\ No newline at end of file
+target_link_libraries(strictasm_diff_ossfuzz PRIVATE libsolc evmasm yulInterpreter FuzzingEngine.a)
+
+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_link_libraries(yul_proto_ossfuzz PRIVATE yul evmasm
+ protobuf-mutator-libfuzzer.a
+ protobuf-mutator.a
+ protobuf.a
+ FuzzingEngine.a)
+
+add_executable(yul_proto_diff_ossfuzz yulProto_diff_ossfuzz.cpp yulFuzzerCommon.cpp protoToYul.cpp yulProto.pb.cc)
+target_include_directories(yul_proto_diff_ossfuzz PRIVATE /src/libprotobuf-mutator /src/LPM/external.protobuf/include)
+target_link_libraries(yul_proto_diff_ossfuzz PRIVATE yul evmasm
+ yulInterpreter
+ protobuf-mutator-libfuzzer.a
+ protobuf-mutator.a
+ protobuf.a
+ FuzzingEngine.a)
diff --git a/test/tools/ossfuzz/protoToYul.cpp b/test/tools/ossfuzz/protoToYul.cpp
new file mode 100644
index 000000000..c7df387e2
--- /dev/null
+++ b/test/tools/ossfuzz/protoToYul.cpp
@@ -0,0 +1,242 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+
+using namespace std;
+using namespace yul::test::yul_fuzzer;
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, Literal const& _x)
+{
+ return _os << "(" << _x.val() << ")";
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, VarRef const& _x)
+{
+ return _os << "x_" << (static_cast(_x.varnum()) % 10);
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, Expression const& _x)
+{
+ if (_x.has_varref())
+ return _os << _x.varref();
+ else if (_x.has_cons())
+ return _os << _x.cons();
+ else if (_x.has_binop())
+ return _os << _x.binop();
+ else if (_x.has_unop())
+ return _os << _x.unop();
+ return _os << "";
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, BinaryOp const& _x)
+{
+ switch (_x.op())
+ {
+ case BinaryOp::ADD:
+ _os << "add(";
+ break;
+ case BinaryOp::SUB:
+ _os << "sub(";
+ break;
+ case BinaryOp::MUL:
+ _os << "mul(";
+ break;
+ case BinaryOp::DIV:
+ _os << "div(";
+ break;
+ case BinaryOp::MOD:
+ _os << "mod(";
+ break;
+ case BinaryOp::XOR:
+ _os << "xor(";
+ break;
+ case BinaryOp::AND:
+ _os << "and(";
+ break;
+ case BinaryOp::OR:
+ _os << "or(";
+ break;
+ case BinaryOp::EQ:
+ _os << "eq(";
+ break;
+ case BinaryOp::LT:
+ _os << "lt(";
+ break;
+ case BinaryOp::GT:
+ _os << "gt(";
+ break;
+ }
+ return _os << _x.left() << "," << _x.right() << ")";
+}
+
+// New var numbering starts from x_10 until x_16
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, VarDecl const& _x)
+{
+ _os << "let x_" << ((_x.id() % 7) + 10) << " := " << _x.expr() << "\n";
+ return _os;
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, TypedVarDecl const& _x)
+{
+ _os << "let x_" << ((_x.id() % 7) + 10);
+ switch (_x.type())
+ {
+ case TypedVarDecl::BOOL:
+ _os << ": bool := " << _x.expr() << " : bool\n";
+ break;
+ case TypedVarDecl::S8:
+ _os << ": s8 := " << _x.expr() << " : s8\n";
+ break;
+ case TypedVarDecl::S32:
+ _os << ": s32 := " << _x.expr() << " : s32\n";
+ break;
+ case TypedVarDecl::S64:
+ _os << ": s64 := " << _x.expr() << " : s64\n";
+ break;
+ case TypedVarDecl::S128:
+ _os << ": s128 := " << _x.expr() << " : s128\n";
+ break;
+ case TypedVarDecl::S256:
+ _os << ": s256 := " << _x.expr() << " : s256\n";
+ break;
+ case TypedVarDecl::U8:
+ _os << ": u8 := " << _x.expr() << " : u8\n";
+ break;
+ case TypedVarDecl::U32:
+ _os << ": u32 := " << _x.expr() << " : u32\n";
+ break;
+ case TypedVarDecl::U64:
+ _os << ": u64 := " << _x.expr() << " : u64\n";
+ break;
+ case TypedVarDecl::U128:
+ _os << ": u128 := " << _x.expr() << " : u128\n";
+ break;
+ case TypedVarDecl::U256:
+ _os << ": u256 := " << _x.expr() << " : u256\n";
+ break;
+ }
+ return _os;
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, UnaryOp const& _x)
+{
+ switch (_x.op())
+ {
+ case UnaryOp::NOT:
+ _os << "not(";
+ break;
+ case UnaryOp::MLOAD:
+ _os << "mload(";
+ break;
+ case UnaryOp::SLOAD:
+ _os << "sload(";
+ break;
+ case UnaryOp::ISZERO:
+ _os << "iszero(";
+ break;
+ }
+ _os << _x.operand() << ")";
+ return _os;
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, AssignmentStatement const& _x)
+{
+ return _os << _x.ref_id() << " := " << _x.expr() << "\n";
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, IfStmt const& _x)
+{
+ return _os <<
+ "if " <<
+ _x.cond() <<
+ " " <<
+ _x.if_body();
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, StoreFunc const& _x)
+{
+ switch (_x.st())
+ {
+ case StoreFunc::MSTORE:
+ _os << "mstore(" << _x.loc() << ", " << _x.val() << ")\n";
+ break;
+ case StoreFunc::SSTORE:
+ _os << "sstore(" << _x.loc() << ", " << _x.val() << ")\n";
+ break;
+ }
+ return _os;
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, Statement const& _x)
+{
+ if (_x.has_decl())
+ return _os << _x.decl();
+ else if (_x.has_assignment())
+ return _os << _x.assignment();
+ else if (_x.has_ifstmt())
+ return _os << _x.ifstmt();
+ else if (_x.has_storage_func())
+ return _os << _x.storage_func();
+ else if (_x.has_blockstmt())
+ return _os << _x.blockstmt();
+ return _os << "";
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, Block const& _x)
+{
+ if (_x.statements_size() > 0)
+ {
+ _os << "{\n";
+ for (auto const& st: _x.statements())
+ _os << st;
+ _os << "}\n";
+
+ }
+ return _os;
+}
+
+ostream& yul::test::yul_fuzzer::operator<<(ostream& _os, Function const& _x)
+{
+ _os << "{\n"
+ << "let a,b := foo(calldataload(0),calldataload(32),calldataload(64),calldataload(96),calldataload(128),"
+ << "calldataload(160),calldataload(192),calldataload(224))\n"
+ << "sstore(0, a)\n"
+ << "sstore(32, b)\n"
+ << "function foo(x_0, x_1, x_2, x_3, x_4, x_5, x_6, x_7) -> x_8, x_9\n"
+ << _x.statements()
+ << "}\n";
+ return _os;
+}
+
+string yul::test::yul_fuzzer::functionToString(Function const& _input)
+{
+ ostringstream os;
+ os << _input;
+ return os.str();
+}
+
+string yul::test::yul_fuzzer::protoToYul(const uint8_t* _data, size_t _size)
+{
+ Function message;
+ if (!message.ParsePartialFromArray(_data, _size))
+ return "#error invalid proto\n";
+ return functionToString(message);
+}
\ No newline at end of file
diff --git a/test/tools/ossfuzz/protoToYul.h b/test/tools/ossfuzz/protoToYul.h
new file mode 100644
index 000000000..14389c547
--- /dev/null
+++ b/test/tools/ossfuzz/protoToYul.h
@@ -0,0 +1,51 @@
+/*
+ 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 .
+*/
+
+#include
+#include
+#include
+
+#include
+
+namespace yul
+{
+namespace test
+{
+namespace yul_fuzzer
+{
+class Function;
+
+std::string functionToString(Function const& input);
+std::string protoToYul(uint8_t const* data, size_t size);
+std::ostream& operator<<(std::ostream& _os, BinaryOp const& _x);
+std::ostream& operator<<(std::ostream& _os, Block const& _x);
+std::ostream& operator<<(std::ostream& _os, Literal const& _x);
+std::ostream& operator<<(std::ostream& _os, VarRef const& _x);
+std::ostream& operator<<(std::ostream& _os, Expression const& _x);
+std::ostream& operator<<(std::ostream& _os, BinaryOp const& _x);
+std::ostream& operator<<(std::ostream& _os, VarDecl const& _x);
+std::ostream& operator<<(std::ostream& _os, TypedVarDecl const& _x);
+std::ostream& operator<<(std::ostream& _os, UnaryOp const& _x);
+std::ostream& operator<<(std::ostream& _os, AssignmentStatement const& _x);
+std::ostream& operator<<(std::ostream& _os, IfStmt const& _x);
+std::ostream& operator<<(std::ostream& _os, StoreFunc const& _x);
+std::ostream& operator<<(std::ostream& _os, Statement const& _x);
+std::ostream& operator<<(std::ostream& _os, Block const& _x);
+std::ostream& operator<<(std::ostream& _os, Function const& _x);
+}
+}
+}
\ No newline at end of file
diff --git a/test/tools/ossfuzz/yulProto.proto b/test/tools/ossfuzz/yulProto.proto
new file mode 100644
index 000000000..470e2a36f
--- /dev/null
+++ b/test/tools/ossfuzz/yulProto.proto
@@ -0,0 +1,156 @@
+/*
+ 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 .
+*/
+
+syntax = "proto2";
+
+// VariableDeclaration =
+// 'let' TypedIdentifierList ( ':=' Expression )?
+// TypedIdentifierList = Identifier ':' TypeName ( ',' Identifier ':' TypeName )*
+// Identifier = [a-zA-Z_$] [a-zA-Z_$0-9]*
+// IdentifierList = Identifier ( ',' Identifier)*
+// TypeName = Identifier | BuiltinTypeName
+// BuiltinTypeName = 'bool' | [us] ( '8' | '32' | '64' | '128' | '256' )
+message VarDecl {
+ required int32 id = 1;
+ required Expression expr = 3;
+}
+
+message TypedVarDecl {
+ enum TypeName {
+ BOOL = 1;
+ U8 = 2;
+ U32 = 3;
+ U64 = 4;
+ U128 = 5;
+ U256 = 6;
+ S8 = 7;
+ S32 = 8;
+ S64 = 9;
+ S128 = 10;
+ S256 = 11;
+ };
+ required int32 id = 1;
+ required TypeName type = 2;
+ required Expression expr = 3;
+}
+
+message VarRef {
+ required int32 varnum = 1;
+}
+
+message Literal {
+ required int32 val = 1;
+}
+
+message TypedLiteral {
+ enum TypeName {
+ BOOL = 1;
+ U8 = 2;
+ U32 = 3;
+ U64 = 4;
+ U128 = 5;
+ U256 = 6;
+ S8 = 7;
+ S32 = 8;
+ S64 = 9;
+ S128 = 10;
+ S256 = 11;
+ };
+ required int32 val = 1;
+ required TypeName type = 2;
+}
+
+message BinaryOp {
+ enum BOp {
+ ADD = 0;
+ SUB = 1;
+ MUL = 2;
+ DIV = 3;
+ MOD = 4;
+ XOR = 5;
+ AND = 6;
+ OR = 7;
+ EQ = 8;
+ LT = 9;
+ GT = 10;
+ };
+ required BOp op = 1;
+ required Expression left = 2;
+ required Expression right = 3;
+}
+
+message UnaryOp {
+ enum UOp {
+ NOT = 0;
+ MLOAD = 1;
+ SLOAD = 2;
+ ISZERO = 3;
+ }
+ required UOp op = 1;
+ required Expression operand = 2;
+}
+
+message StoreFunc {
+ enum Storage {
+ MSTORE = 0;
+ SSTORE = 1;
+ }
+ required Expression loc = 1;
+ required Expression val = 2;
+ required Storage st = 3;
+}
+
+message Expression {
+ oneof expr_oneof {
+ VarRef varref = 1;
+ Literal cons = 2;
+ BinaryOp binop = 3;
+ UnaryOp unop = 4;
+ }
+}
+
+message AssignmentStatement {
+ required VarRef ref_id = 1;
+ required Expression expr = 2;
+}
+
+message IfStmt {
+ required Expression cond = 1;
+ required Block if_body = 2;
+}
+
+// add for loop
+// TODO: add block and scope for if
+message Statement {
+ oneof stmt_oneof {
+ VarDecl decl = 1;
+ AssignmentStatement assignment = 2;
+ IfStmt ifstmt = 3;
+ StoreFunc storage_func = 4;
+ Block blockstmt = 5;
+ }
+}
+
+message Block {
+ repeated Statement statements = 1;
+}
+
+message Function {
+ required Block statements = 1;
+}
+
+package yul.test.yul_fuzzer;
diff --git a/test/tools/ossfuzz/yulProtoFuzzer.cpp b/test/tools/ossfuzz/yulProtoFuzzer.cpp
new file mode 100644
index 000000000..b959bc1d8
--- /dev/null
+++ b/test/tools/ossfuzz/yulProtoFuzzer.cpp
@@ -0,0 +1,59 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+using namespace yul;
+using namespace yul::test::yul_fuzzer;
+using namespace std;
+
+DEFINE_BINARY_PROTO_FUZZER(Function const& _input)
+{
+ string yul_source = functionToString(_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(yul_source.data(), yul_source.size());
+ }
+
+ // AssemblyStack entry point
+ AssemblyStack stack(langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly);
+
+ // Parse protobuf mutated YUL code
+ if (!stack.parseAndAnalyze("source", yul_source))
+ return;
+
+ yulAssert(stack.errors().empty(), "Parsed successfully but had errors.");
+
+ if (!stack.parserResult()->code || !stack.parserResult()->analysisInfo)
+ return;
+
+ // Optimize
+ stack.optimize();
+}
\ No newline at end of file
diff --git a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp
new file mode 100644
index 000000000..0d210e092
--- /dev/null
+++ b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp
@@ -0,0 +1,75 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+
+using namespace yul;
+using namespace yul::test::yul_fuzzer;
+using namespace std;
+
+using namespace langutil;
+using namespace dev;
+using namespace yul::test;
+
+DEFINE_BINARY_PROTO_FUZZER(Function const& _input)
+{
+ string yul_source = functionToString(_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(yul_source.data(), yul_source.size());
+ }
+
+ // AssemblyStack entry point
+ AssemblyStack stack(langutil::EVMVersion(), AssemblyStack::Language::StrictAssembly);
+
+ try
+ {
+ // Parse protobuf mutated YUL code
+ if (!stack.parseAndAnalyze("source", yul_source) || !stack.parserResult()->code ||
+ !stack.parserResult()->analysisInfo)
+ return;
+ }
+ catch (Exception const&)
+ {
+ return;
+ }
+
+ ostringstream os1;
+ ostringstream os2;
+ yulFuzzerUtil::interpret(os1, stack.parserResult()->code);
+ stack.optimize();
+ yulFuzzerUtil::interpret(os2, stack.parserResult()->code);
+
+ bool isTraceEq = (os1.str() == os2.str());
+ yulAssert(isTraceEq, "Interpreted traces for optimized and unoptimized code differ.");
+ return;
+}
\ No newline at end of file