-
-
Save chibitanaka/6371ef48b7b06ac8c618d44fe9f38dea to your computer and use it in GitHub Desktop.
Solidity compiler patch to generate synthetic Yul contracts via OSS-Fuzz
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/test/tools/ossfuzz/protoToYul.cpp b/test/tools/ossfuzz/protoToYul.cpp | |
index 1719dec46..9a2fd6d54 100644 | |
--- a/test/tools/ossfuzz/protoToYul.cpp | |
+++ b/test/tools/ossfuzz/protoToYul.cpp | |
@@ -39,6 +39,12 @@ using namespace solidity::langutil; | |
using namespace solidity::util; | |
using namespace solidity; | |
+#ifdef NEW_LN_PRINT | |
+#define NEW_LN "\n" | |
+#else | |
+#define NEW_LN " " | |
+#endif | |
+ | |
string ProtoConverter::dictionaryToken(HexPrefix _p) | |
{ | |
std::string token; | |
@@ -446,7 +452,7 @@ void ProtoConverter::visit(VarDecl const& _x) | |
string varName = newVarName(); | |
m_output << "let " << varName << " := "; | |
visit(_x.expr()); | |
- m_output << "\n"; | |
+ m_output << NEW_LN; | |
scopeVariables({varName}); | |
} | |
@@ -466,7 +472,7 @@ void ProtoConverter::visit(MultiVarDecl const& _x) | |
if (i == 0) | |
delimiter = ", "; | |
} | |
- m_output << "\n"; | |
+ m_output << NEW_LN; | |
scopeVariables(varNames); | |
} | |
@@ -479,57 +485,57 @@ void ProtoConverter::visit(TypedVarDecl const& _x) | |
case TypedVarDecl::BOOL: | |
m_output << ": bool := "; | |
visit(_x.expr()); | |
- m_output << " : bool\n"; | |
+ m_output << " : bool" NEW_LN; | |
break; | |
case TypedVarDecl::S8: | |
m_output << ": s8 := "; | |
visit(_x.expr()); | |
- m_output << " : s8\n"; | |
+ m_output << " : s8" NEW_LN; | |
break; | |
case TypedVarDecl::S32: | |
m_output << ": s32 := "; | |
visit(_x.expr()); | |
- m_output << " : s32\n"; | |
+ m_output << " : s32" NEW_LN; | |
break; | |
case TypedVarDecl::S64: | |
m_output << ": s64 := "; | |
visit(_x.expr()); | |
- m_output << " : s64\n"; | |
+ m_output << " : s64" NEW_LN; | |
break; | |
case TypedVarDecl::S128: | |
m_output << ": s128 := "; | |
visit(_x.expr()); | |
- m_output << " : s128\n"; | |
+ m_output << " : s128" NEW_LN; | |
break; | |
case TypedVarDecl::S256: | |
m_output << ": s256 := "; | |
visit(_x.expr()); | |
- m_output << " : s256\n"; | |
+ m_output << " : s256" NEW_LN; | |
break; | |
case TypedVarDecl::U8: | |
m_output << ": u8 := "; | |
visit(_x.expr()); | |
- m_output << " : u8\n"; | |
+ m_output << " : u8" NEW_LN; | |
break; | |
case TypedVarDecl::U32: | |
m_output << ": u32 := "; | |
visit(_x.expr()); | |
- m_output << " : u32\n"; | |
+ m_output << " : u32" NEW_LN; | |
break; | |
case TypedVarDecl::U64: | |
m_output << ": u64 := "; | |
visit(_x.expr()); | |
- m_output << " : u64\n"; | |
+ m_output << " : u64" NEW_LN; | |
break; | |
case TypedVarDecl::U128: | |
m_output << ": u128 := "; | |
visit(_x.expr()); | |
- m_output << " : u128\n"; | |
+ m_output << " : u128" NEW_LN; | |
break; | |
case TypedVarDecl::U256: | |
m_output << ": u256 := "; | |
visit(_x.expr()); | |
- m_output << " : u256\n"; | |
+ m_output << " : u256" NEW_LN; | |
break; | |
} | |
// If we are inside a for-init block, there are two places | |
@@ -849,7 +855,7 @@ void ProtoConverter::visit(CopyFunc const& _x) | |
m_output << "mod("; | |
visit(_x.size()); | |
m_output << ", " << to_string(s_maxSize) << ")"; | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
} | |
void ProtoConverter::visit(ExtCodeCopy const& _x) | |
@@ -867,7 +873,7 @@ void ProtoConverter::visit(ExtCodeCopy const& _x) | |
m_output << "mod("; | |
visit(_x.size()); | |
m_output << ", " << to_string(s_maxSize) << ")"; | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
} | |
void ProtoConverter::visit(LogFunc const& _x) | |
@@ -888,7 +894,7 @@ void ProtoConverter::visit(LogFunc const& _x) | |
m_output << "log0"; | |
m_output << "("; | |
visitPosAndSize(_x); | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
break; | |
case LogFunc::ONE: | |
m_output << "log1"; | |
@@ -896,7 +902,7 @@ void ProtoConverter::visit(LogFunc const& _x) | |
visitPosAndSize(_x); | |
m_output << ", "; | |
visit(_x.t1()); | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
break; | |
case LogFunc::TWO: | |
m_output << "log2"; | |
@@ -906,7 +912,7 @@ void ProtoConverter::visit(LogFunc const& _x) | |
visit(_x.t1()); | |
m_output << ", "; | |
visit(_x.t2()); | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
break; | |
case LogFunc::THREE: | |
m_output << "log3"; | |
@@ -918,7 +924,7 @@ void ProtoConverter::visit(LogFunc const& _x) | |
visit(_x.t2()); | |
m_output << ", "; | |
visit(_x.t3()); | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
break; | |
case LogFunc::FOUR: | |
m_output << "log4"; | |
@@ -932,7 +938,7 @@ void ProtoConverter::visit(LogFunc const& _x) | |
visit(_x.t3()); | |
m_output << ", "; | |
visit(_x.t4()); | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
break; | |
} | |
} | |
@@ -942,7 +948,7 @@ void ProtoConverter::visit(AssignmentStatement const& _x) | |
visit(_x.ref_id()); | |
m_output << " := "; | |
visit(_x.expr()); | |
- m_output << "\n"; | |
+ m_output << NEW_LN; | |
} | |
void ProtoConverter::visitFunctionInputParams(FunctionCall const& _x, unsigned _numInputParams) | |
@@ -984,7 +990,7 @@ void ProtoConverter::convertFunctionCall( | |
visitFunctionInputParams(_x, _numInParams); | |
m_output << ")"; | |
if (_newLine) | |
- m_output << "\n"; | |
+ m_output << NEW_LN; | |
} | |
vector<string> ProtoConverter::createVarDecls(unsigned _start, unsigned _end, bool _isAssignment) | |
@@ -994,7 +1000,7 @@ vector<string> ProtoConverter::createVarDecls(unsigned _start, unsigned _end, bo | |
if (_isAssignment) | |
m_output << " := "; | |
else | |
- m_output << "\n"; | |
+ m_output << NEW_LN; | |
return varsVec; | |
} | |
@@ -1187,7 +1193,7 @@ void ProtoConverter::visit(StoreFunc const& _x) | |
} | |
m_output << ", "; | |
visit(_x.val()); | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
} | |
void ProtoConverter::visit(ForStmt const& _x) | |
@@ -1325,7 +1331,7 @@ void ProtoConverter::visit(SwitchStmt const& _x) | |
m_switchLiteralSetPerScope.push(s); | |
m_output << "switch "; | |
visit(_x.switch_expr()); | |
- m_output << "\n"; | |
+ m_output << NEW_LN; | |
for (auto const& caseStmt: _x.case_stmt()) | |
visit(caseStmt); | |
@@ -1345,10 +1351,10 @@ void ProtoConverter::visit(StopInvalidStmt const& _x) | |
switch (_x.stmt()) | |
{ | |
case StopInvalidStmt::STOP: | |
- m_output << "stop()\n"; | |
+ m_output << "stop()" NEW_LN; | |
break; | |
case StopInvalidStmt::INVALID: | |
- m_output << "invalid()\n"; | |
+ m_output << "invalid()" NEW_LN; | |
break; | |
} | |
} | |
@@ -1372,7 +1378,7 @@ void ProtoConverter::visit(RetRevStmt const& _x) | |
m_output << "mod("; | |
visit(_x.size()); | |
m_output << ", " << to_string(s_maxSize) << ")"; | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
} | |
void ProtoConverter::visit(SelfDestructStmt const& _x) | |
@@ -1380,7 +1386,7 @@ void ProtoConverter::visit(SelfDestructStmt const& _x) | |
m_output << "selfdestruct"; | |
m_output << "("; | |
visit(_x.addr()); | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
} | |
void ProtoConverter::visit(TerminatingStmt const& _x) | |
@@ -1455,11 +1461,11 @@ void ProtoConverter::visit(Statement const& _x) | |
break; | |
case Statement::kBreakstmt: | |
if (m_inForBodyScope) | |
- m_output << "break\n"; | |
+ m_output << "break" NEW_LN; | |
break; | |
case Statement::kContstmt: | |
if (m_inForBodyScope) | |
- m_output << "continue\n"; | |
+ m_output << "continue" NEW_LN; | |
break; | |
case Statement::kLogFunc: | |
// Log is a stateful statement since it writes to storage. | |
@@ -1675,7 +1681,7 @@ void ProtoConverter::visit(Block const& _x) | |
if (_x.statements_size() > 0) | |
{ | |
- m_output << "{\n"; | |
+ m_output << "{" NEW_LN; | |
bool wasForInitScopeExtEnabled = m_forInitScopeExtEnabled; | |
for (auto const& st: _x.statements()) | |
{ | |
@@ -1690,10 +1696,10 @@ void ProtoConverter::visit(Block const& _x) | |
visit(st); | |
m_forInitScopeExtEnabled = wasForInitScopeExtEnabled; | |
} | |
- m_output << "}\n"; | |
+ m_output << "}" NEW_LN; | |
} | |
else | |
- m_output << "{}\n"; | |
+ m_output << "{}" NEW_LN; | |
closeBlockScope(); | |
} | |
@@ -1792,16 +1798,16 @@ void ProtoConverter::saveFunctionCallOutput(vector<string> const& _varsVec) | |
// aligned slots. | |
string slot = std::to_string((counter() % numSlots) * slotSize); | |
if (diceThrow == 0) | |
- m_output << "sstore(" << slot << ", " << var << ")\n"; | |
+ m_output << "sstore(" << slot << ", " << var << ")" NEW_LN; | |
else if (diceThrow == 1) | |
- m_output << "mstore(" << slot << ", " << var << ")\n"; | |
+ m_output << "mstore(" << slot << ", " << var << ")" NEW_LN; | |
else | |
{ | |
yulAssert( | |
m_evmVersion.supportsTransientStorage(), | |
"Proto fuzzer: Invalid evm version" | |
); | |
- m_output << "tstore(" << slot << ", " << var << ")\n"; | |
+ m_output << "tstore(" << slot << ", " << var << ")" NEW_LN; | |
} | |
} | |
} | |
@@ -1828,7 +1834,7 @@ void ProtoConverter::createFunctionCall( | |
m_output << _funcName << "("; | |
if (_numInParams > 0) | |
fillFunctionCallInput(_numInParams); | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
if (!varsVec.empty()) | |
{ | |
@@ -1882,7 +1888,7 @@ void ProtoConverter::createFunctionDefAndCall( | |
} | |
yulAssert(varsVec.size() == _numInParams + _numOutParams, "Proto fuzzer: Function parameters not processed correctly"); | |
- m_output << "\n"; | |
+ m_output << NEW_LN; | |
// If function definition is in for-loop body, update | |
bool wasInForBody = m_inForBodyScope; | |
@@ -1920,12 +1926,12 @@ void ProtoConverter::visit(PopStmt const& _x) | |
{ | |
m_output << "pop("; | |
visit(_x.expr()); | |
- m_output << ")\n"; | |
+ m_output << ")" NEW_LN; | |
} | |
void ProtoConverter::visit(LeaveStmt const&) | |
{ | |
- m_output << "leave\n"; | |
+ m_output << "leave" NEW_LN; | |
} | |
string ProtoConverter::getObjectIdentifier(unsigned _x) | |
@@ -1942,15 +1948,15 @@ string ProtoConverter::getObjectIdentifier(unsigned _x) | |
void ProtoConverter::visit(Code const& _x) | |
{ | |
- m_output << "code {\n"; | |
+ m_output << "code {" NEW_LN; | |
visit(_x.block()); | |
- m_output << "}\n"; | |
+ m_output << "}" NEW_LN; | |
} | |
void ProtoConverter::visit(Data const& _x) | |
{ | |
// TODO: Generate random data block identifier | |
- m_output << "data \"" << s_dataIdentifier << "\" hex\"" << createHex(_x.hex()) << "\"\n"; | |
+ m_output << "data \"" << s_dataIdentifier << "\" hex\"" << createHex(_x.hex()) << "\"" NEW_LN; | |
} | |
void ProtoConverter::visit(Object const& _x) | |
@@ -1958,13 +1964,13 @@ void ProtoConverter::visit(Object const& _x) | |
// object "object<n>" { | |
// ... | |
// } | |
- m_output << "object " << newObjectId() << " {\n"; | |
+ m_output << "object " << newObjectId() << " {" NEW_LN; | |
visit(_x.code()); | |
if (_x.has_data()) | |
visit(_x.data()); | |
for (auto const& subObj: _x.sub_obj()) | |
visit(subObj); | |
- m_output << "}\n"; | |
+ m_output << "}" NEW_LN; | |
} | |
void ProtoConverter::buildObjectScopeTree(Object const& _x) | |
@@ -2004,11 +2010,11 @@ void ProtoConverter::visit(Program const& _x) | |
switch (_x.program_oneof_case()) | |
{ | |
case Program::kBlock: | |
- m_output << "{\n"; | |
- m_output << "mstore(memoryguard(0x10000), 1)\n"; | |
- m_output << "sstore(mload(calldataload(0)), 1)\n"; | |
+ m_output << "{" NEW_LN; | |
+ m_output << "mstore(memoryguard(0x10000), 1)" NEW_LN; | |
+ m_output << "sstore(mload(calldataload(0)), 1)" NEW_LN; | |
visit(_x.block()); | |
- m_output << "}\n"; | |
+ m_output << "}" NEW_LN; | |
break; | |
case Program::kObj: | |
m_isObject = true; | |
diff --git a/test/tools/ossfuzz/yulProtoFuzzer.cpp b/test/tools/ossfuzz/yulProtoFuzzer.cpp | |
index c2ac68093..376cc3e52 100644 | |
--- a/test/tools/ossfuzz/yulProtoFuzzer.cpp | |
+++ b/test/tools/ossfuzz/yulProtoFuzzer.cpp | |
@@ -35,6 +35,8 @@ | |
#include <src/libfuzzer/libfuzzer_macro.h> | |
+#include <libsolutil/JSON.h> | |
+ | |
using namespace solidity; | |
using namespace solidity::langutil; | |
using namespace solidity::yul; | |
@@ -48,15 +50,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) | |
string yul_source = converter.programToString(_input); | |
EVMVersion version = converter.version(); | |
- 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(), static_cast<streamsize>(yul_source.size())); | |
- } | |
- | |
- if (yul_source.size() > 1200) | |
+ if (yul_source.size() < 1000) | |
return; | |
YulStringRepository::reset(); | |
@@ -79,6 +73,19 @@ DEFINE_PROTO_FUZZER(Program const& _input) | |
) | |
yulAssert(false, "Proto fuzzer generated malformed program"); | |
+ 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(), static_cast<streamsize>(yul_source.size())); | |
+ string yul_ast = solidity::util::jsonCompactPrint(stack.astJson()); | |
+ const string ast_delim = "\n|AST_DELIM|"; | |
+ of.write(ast_delim.data(), static_cast<streamsize>(ast_delim.size())); | |
+ of.write(yul_ast.data(), static_cast<streamsize>(yul_ast.size())); | |
+ | |
+ } | |
+ | |
// Optimize | |
YulOptimizerTestCommon optimizerTest( | |
stack.parserResult(), |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment