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.");
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())
{

View File

@ -66,6 +66,8 @@
#include <libsolidity/interface/OptimiserSettings.h>
#include <random>
using namespace solidity;
using namespace solidity::util;
using namespace solidity::langutil;
@ -76,15 +78,13 @@ using namespace std;
YulOptimizerTestCommon::YulOptimizerTestCommon(
shared_ptr<Object> _obj,
Dialect const& _dialect,
string const& _optimizerStep
Dialect const& _dialect
)
{
m_object = _obj;
m_ast = m_object->code;
m_analysisInfo = m_object->analysisInfo;
m_dialect = &_dialect;
m_optimizerStep = _optimizerStep;
m_namedSteps = {
{"disambiguator", [&]() { disambiguate(); }},
@ -360,6 +360,11 @@ YulOptimizerTestCommon::YulOptimizerTestCommon(
};
}
void YulOptimizerTestCommon::setStep(string const& _optimizerStep)
{
m_optimizerStep = _optimizerStep;
}
bool YulOptimizerTestCommon::runStep()
{
yulAssert(m_dialect, "Dialect not set.");
@ -374,6 +379,31 @@ bool YulOptimizerTestCommon::runStep()
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()
{
return runStep() ? m_ast : nullptr;

View File

@ -40,15 +40,22 @@ class YulOptimizerTestCommon
public:
explicit YulOptimizerTestCommon(
std::shared_ptr<Object> _obj,
Dialect const& _dialect,
std::string const& _optimizerStep
Dialect const& _dialect
);
/// Sets optimiser step to be run to @param
/// _optimiserStep.
void setStep(std::string const& _optimizerStep);
/// Runs chosen optimiser step returning pointer
/// to yul AST Block post optimisation.
std::shared_ptr<Block> run();
/// Runs chosen optimiser step returning true if
/// successful, false otherwise.
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:
void disambiguate();
void updateContext();

View File

@ -76,7 +76,12 @@ if (OSSFUZZ)
target_link_libraries(strictasm_assembly_ossfuzz PRIVATE yul)
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_link_libraries(yul_proto_ossfuzz PRIVATE yul
protobuf-mutator-libfuzzer.a
@ -86,7 +91,14 @@ if (OSSFUZZ)
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)
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_link_libraries(yul_proto_diff_ossfuzz PRIVATE yul
yulInterpreter
@ -103,6 +115,7 @@ if (OSSFUZZ)
protoToYul.cpp
yulProto.pb.cc
protomutators/YulProtoMutator.cpp
../../libyul/YulOptimizerTestCommon.cpp
)
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

View File

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

View File

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

View File

@ -19,16 +19,24 @@
#include <fstream>
#include <test/tools/ossfuzz/yulProto.pb.h>
#include <test/tools/fuzzer_common.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 <liblangutil/EVMVersion.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::yul;
using namespace solidity::yul::test;
using namespace solidity::yul::test::yul_fuzzer;
using namespace solidity::langutil;
using namespace std;
@ -69,5 +77,11 @@ DEFINE_PROTO_FUZZER(Program const& _input)
yulAssert(false, "Proto fuzzer generated malformed program");
// 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/fuzzer_common.h>
#include <test/tools/ossfuzz/protoToYul.h>
#include <test/libyul/YulOptimizerTestCommon.h>
#include <src/libfuzzer/libfuzzer_macro.h>
#include <libyul/AssemblyStack.h>
@ -104,10 +107,16 @@ DEFINE_PROTO_FUZZER(Program const& _input)
)
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(
os2,
stack.parserResult()->code,
astBlock,
EVMDialect::strictAssemblyForEVMObjects(version)
);
if (