Enable fine grained yul optimizer fuzzing

This commit is contained in:
Bhargava Shastry 2020-10-07 14:04:00 +02:00
parent 0b023b893e
commit b3dd83a20b
8 changed files with 89 additions and 15 deletions

View File

@ -74,7 +74,8 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
soltestAssert(m_dialect, "Dialect not set."); soltestAssert(m_dialect, "Dialect not set.");
m_object->analysisInfo = m_analysisInfo; m_object->analysisInfo = m_analysisInfo;
YulOptimizerTestCommon tester(m_object, *m_dialect, m_optimizerStep); YulOptimizerTestCommon tester(m_object, *m_dialect);
tester.setStep(m_optimizerStep);
if (!tester.runStep()) if (!tester.runStep())
{ {

View File

@ -66,6 +66,8 @@
#include <libsolidity/interface/OptimiserSettings.h> #include <libsolidity/interface/OptimiserSettings.h>
#include <random>
using namespace solidity; using namespace solidity;
using namespace solidity::util; using namespace solidity::util;
using namespace solidity::langutil; using namespace solidity::langutil;
@ -76,15 +78,13 @@ using namespace std;
YulOptimizerTestCommon::YulOptimizerTestCommon( YulOptimizerTestCommon::YulOptimizerTestCommon(
shared_ptr<Object> _obj, shared_ptr<Object> _obj,
Dialect const& _dialect, Dialect const& _dialect
string const& _optimizerStep
) )
{ {
m_object = _obj; m_object = _obj;
m_ast = m_object->code; m_ast = m_object->code;
m_analysisInfo = m_object->analysisInfo; m_analysisInfo = m_object->analysisInfo;
m_dialect = &_dialect; m_dialect = &_dialect;
m_optimizerStep = _optimizerStep;
m_namedSteps = { m_namedSteps = {
{"disambiguator", [&]() { disambiguate(); }}, {"disambiguator", [&]() { disambiguate(); }},
@ -360,6 +360,11 @@ YulOptimizerTestCommon::YulOptimizerTestCommon(
}; };
} }
void YulOptimizerTestCommon::setStep(string const& _optimizerStep)
{
m_optimizerStep = _optimizerStep;
}
bool YulOptimizerTestCommon::runStep() bool YulOptimizerTestCommon::runStep()
{ {
yulAssert(m_dialect, "Dialect not set."); yulAssert(m_dialect, "Dialect not set.");
@ -374,6 +379,31 @@ bool YulOptimizerTestCommon::runStep()
return true; return true;
} }
string YulOptimizerTestCommon::randomOptimiserStep(unsigned _seed)
{
std::mt19937 prng(_seed);
std::uniform_int_distribution<size_t> dist(1, m_namedSteps.size());
size_t idx = dist(prng);
size_t count = 1;
for (auto &step: m_namedSteps)
{
if (count == idx)
{
string optimiserStep = step.first;
// Do not fuzz mainFunction or wordSizeTransform
// because they do not preserve yul code semantics.
if (optimiserStep == "mainFunction" || optimiserStep == "wordSizeTransform")
// "Fullsuite" is fuzzed roughly three times more frequently than
// other steps because of the filtering in place above.
return "fullSuite";
else
return optimiserStep;
}
count++;
}
yulAssert(false, "Optimiser step selection failed.");
}
shared_ptr<Block> YulOptimizerTestCommon::run() shared_ptr<Block> YulOptimizerTestCommon::run()
{ {
return runStep() ? m_ast : nullptr; return runStep() ? m_ast : nullptr;

View File

@ -40,15 +40,22 @@ class YulOptimizerTestCommon
public: public:
explicit YulOptimizerTestCommon( explicit YulOptimizerTestCommon(
std::shared_ptr<Object> _obj, std::shared_ptr<Object> _obj,
Dialect const& _dialect, Dialect const& _dialect
std::string const& _optimizerStep
); );
/// Sets optimiser step to be run to @param
/// _optimiserStep.
void setStep(std::string const& _optimizerStep);
/// Runs chosen optimiser step returning pointer /// Runs chosen optimiser step returning pointer
/// to yul AST Block post optimisation. /// to yul AST Block post optimisation.
std::shared_ptr<Block> run(); std::shared_ptr<Block> run();
/// Runs chosen optimiser step returning true if /// Runs chosen optimiser step returning true if
/// successful, false otherwise. /// successful, false otherwise.
bool runStep(); bool runStep();
/// Returns the string name of a randomly chosen
/// optimiser step.
/// @param _seed is an unsigned integer that
/// seeds the random selection.
std::string randomOptimiserStep(unsigned _seed);
private: private:
void disambiguate(); void disambiguate();
void updateContext(); void updateContext();

View File

@ -76,7 +76,12 @@ if (OSSFUZZ)
target_link_libraries(strictasm_assembly_ossfuzz PRIVATE yul) target_link_libraries(strictasm_assembly_ossfuzz PRIVATE yul)
set_target_properties(strictasm_assembly_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) set_target_properties(strictasm_assembly_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
add_executable(yul_proto_ossfuzz yulProtoFuzzer.cpp protoToYul.cpp yulProto.pb.cc) add_executable(yul_proto_ossfuzz
yulProtoFuzzer.cpp
protoToYul.cpp
yulProto.pb.cc
../../libyul/YulOptimizerTestCommon.cpp
)
target_include_directories(yul_proto_ossfuzz PRIVATE /usr/include/libprotobuf-mutator) target_include_directories(yul_proto_ossfuzz PRIVATE /usr/include/libprotobuf-mutator)
target_link_libraries(yul_proto_ossfuzz PRIVATE yul target_link_libraries(yul_proto_ossfuzz PRIVATE yul
protobuf-mutator-libfuzzer.a protobuf-mutator-libfuzzer.a
@ -86,7 +91,14 @@ if (OSSFUZZ)
set_target_properties(yul_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) set_target_properties(yul_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
target_compile_options(yul_proto_ossfuzz PUBLIC ${COMPILE_OPTIONS} -Wno-sign-conversion -Wno-suggest-destructor-override -Wno-inconsistent-missing-destructor-override) target_compile_options(yul_proto_ossfuzz PUBLIC ${COMPILE_OPTIONS} -Wno-sign-conversion -Wno-suggest-destructor-override -Wno-inconsistent-missing-destructor-override)
add_executable(yul_proto_diff_ossfuzz yulProto_diff_ossfuzz.cpp yulFuzzerCommon.cpp protoToYul.cpp yulProto.pb.cc) add_executable(
yul_proto_diff_ossfuzz
yulProto_diff_ossfuzz.cpp
yulFuzzerCommon.cpp
protoToYul.cpp
yulProto.pb.cc
../../libyul/YulOptimizerTestCommon.cpp
)
target_include_directories(yul_proto_diff_ossfuzz PRIVATE /usr/include/libprotobuf-mutator) target_include_directories(yul_proto_diff_ossfuzz PRIVATE /usr/include/libprotobuf-mutator)
target_link_libraries(yul_proto_diff_ossfuzz PRIVATE yul target_link_libraries(yul_proto_diff_ossfuzz PRIVATE yul
yulInterpreter yulInterpreter
@ -103,6 +115,7 @@ if (OSSFUZZ)
protoToYul.cpp protoToYul.cpp
yulProto.pb.cc yulProto.pb.cc
protomutators/YulProtoMutator.cpp protomutators/YulProtoMutator.cpp
../../libyul/YulOptimizerTestCommon.cpp
) )
target_include_directories(yul_proto_diff_custom_mutate_ossfuzz PRIVATE /usr/include/libprotobuf-mutator) target_include_directories(yul_proto_diff_custom_mutate_ossfuzz PRIVATE /usr/include/libprotobuf-mutator)
target_link_libraries(yul_proto_diff_custom_mutate_ossfuzz PRIVATE yul target_link_libraries(yul_proto_diff_custom_mutate_ossfuzz PRIVATE yul

View File

@ -64,7 +64,6 @@ public:
{ {
return m_evmVersion; return m_evmVersion;
} }
private: private:
void visit(BinaryOp const&); void visit(BinaryOp const&);

View File

@ -415,6 +415,7 @@ message Program {
Object obj = 2; Object obj = 2;
} }
required Version ver = 3; required Version ver = 3;
required uint32 step = 4;
} }
package solidity.yul.test.yul_fuzzer; package solidity.yul.test.yul_fuzzer;

View File

@ -19,16 +19,24 @@
#include <fstream> #include <fstream>
#include <test/tools/ossfuzz/yulProto.pb.h> #include <test/tools/ossfuzz/yulProto.pb.h>
#include <test/tools/fuzzer_common.h>
#include <test/tools/ossfuzz/protoToYul.h> #include <test/tools/ossfuzz/protoToYul.h>
#include <src/libfuzzer/libfuzzer_macro.h>
#include <test/tools/fuzzer_common.h>
#include <test/libyul/YulOptimizerTestCommon.h>
#include <libyul/AssemblyStack.h> #include <libyul/AssemblyStack.h>
#include <liblangutil/EVMVersion.h>
#include <libyul/Exceptions.h> #include <libyul/Exceptions.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <liblangutil/EVMVersion.h>
#include <src/libfuzzer/libfuzzer_macro.h>
using namespace solidity; using namespace solidity;
using namespace solidity::yul; using namespace solidity::yul;
using namespace solidity::yul::test;
using namespace solidity::yul::test::yul_fuzzer; using namespace solidity::yul::test::yul_fuzzer;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace std; using namespace std;
@ -69,5 +77,11 @@ DEFINE_PROTO_FUZZER(Program const& _input)
yulAssert(false, "Proto fuzzer generated malformed program"); yulAssert(false, "Proto fuzzer generated malformed program");
// Optimize // Optimize
stack.optimize(); YulOptimizerTestCommon optimizerTest(
stack.parserResult(),
EVMDialect::strictAssemblyForEVMObjects(version)
);
optimizerTest.setStep(optimizerTest.randomOptimiserStep(_input.step()));
shared_ptr<solidity::yul::Block> astBlock = optimizerTest.run();
yulAssert(astBlock != nullptr, "Optimiser error.");
} }

View File

@ -21,6 +21,9 @@
#include <test/tools/ossfuzz/yulProto.pb.h> #include <test/tools/ossfuzz/yulProto.pb.h>
#include <test/tools/fuzzer_common.h> #include <test/tools/fuzzer_common.h>
#include <test/tools/ossfuzz/protoToYul.h> #include <test/tools/ossfuzz/protoToYul.h>
#include <test/libyul/YulOptimizerTestCommon.h>
#include <src/libfuzzer/libfuzzer_macro.h> #include <src/libfuzzer/libfuzzer_macro.h>
#include <libyul/AssemblyStack.h> #include <libyul/AssemblyStack.h>
@ -104,10 +107,16 @@ DEFINE_PROTO_FUZZER(Program const& _input)
) )
return; return;
stack.optimize(); YulOptimizerTestCommon optimizerTest(
stack.parserResult(),
EVMDialect::strictAssemblyForEVMObjects(version)
);
optimizerTest.setStep(optimizerTest.randomOptimiserStep(_input.step()));
shared_ptr<solidity::yul::Block> astBlock = optimizerTest.run();
yulAssert(astBlock != nullptr, "Optimiser error.");
termReason = yulFuzzerUtil::interpret( termReason = yulFuzzerUtil::interpret(
os2, os2,
stack.parserResult()->code, astBlock,
EVMDialect::strictAssemblyForEVMObjects(version) EVMDialect::strictAssemblyForEVMObjects(version)
); );
if ( if (