Skip to content

Instantly share code, notes, and snippets.

@chibitanaka
Created May 31, 2024 11:26
Show Gist options
  • Save chibitanaka/6371ef48b7b06ac8c618d44fe9f38dea to your computer and use it in GitHub Desktop.
Save chibitanaka/6371ef48b7b06ac8c618d44fe9f38dea to your computer and use it in GitHub Desktop.
Solidity compiler patch to generate synthetic Yul contracts via OSS-Fuzz
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