From 68146e7c28e21ad3537894a20dd6a1e60c84ded6 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Thu, 13 Aug 2020 13:32:26 +0200 Subject: [PATCH] Draft --- test/tools/fuzzer_common.cpp | 102 +++++++++++++++++++++++- test/tools/fuzzer_common.h | 2 + test/tools/ossfuzz/CMakeLists.txt | 14 +++- test/tools/ossfuzz/solc_opt_ossfuzz.cpp | 2 +- test/tools/ossfuzz/yulFuzzerCommon.h | 2 +- 5 files changed, 117 insertions(+), 5 deletions(-) diff --git a/test/tools/fuzzer_common.cpp b/test/tools/fuzzer_common.cpp index 9b0909bb3..3ca84f29e 100644 --- a/test/tools/fuzzer_common.cpp +++ b/test/tools/fuzzer_common.cpp @@ -29,6 +29,11 @@ #include +#include + +#include + +#include #include using namespace std; @@ -36,6 +41,22 @@ using namespace solidity; using namespace solidity::util; using namespace solidity::evmasm; using namespace solidity::langutil; +using namespace solidity::yul; +using namespace solidity::yul::test::yul_fuzzer; + +namespace +{ +void printErrors(ostream& _stream, ErrorList const& _errors) +{ + SourceReferenceFormatter formatter(_stream); + + for (auto const& error: _errors) + formatter.printExceptionInformation( + *error, + (error->type() == Error::Type::Warning) ? "Warning" : "Error" + ); +} +} static vector s_evmVersions = { EVMVersion::homestead(), @@ -81,6 +102,73 @@ void FuzzerUtil::forceSMT(StringMap& _input) sourceUnit.second += smtPragma; } +void FuzzerUtil::yulIRDiff(EVMVersion _version, string const& _ir, string const& _irOpt) +{ + YulStringRepository::reset(); + + if (_ir.empty() && _irOpt.empty()) + return; + + // AssemblyStack entry point + AssemblyStack stackIr( + _version, + AssemblyStack::Language::StrictAssembly, + solidity::frontend::OptimiserSettings::full() + ); + + // Parse protobuf mutated YUL code + if ( + !stackIr.parseAndAnalyze("source", _ir) || + !stackIr.parserResult()->code || + !stackIr.parserResult()->analysisInfo || + !Error::containsOnlyWarnings(stackIr.errors()) + ) + { + std::cout << _ir << std::endl; + printErrors(std::cout, stackIr.errors()); + yulAssert(false, "Compiler generated malformed IR"); + } + + AssemblyStack stackIrOpt( + _version, + AssemblyStack::Language::StrictAssembly, + solidity::frontend::OptimiserSettings::full() + ); + + // Parse protobuf mutated YUL code + if ( + !stackIrOpt.parseAndAnalyze("source", _irOpt) || + !stackIrOpt.parserResult()->code || + !stackIrOpt.parserResult()->analysisInfo || + !Error::containsOnlyWarnings(stackIrOpt.errors()) + ) + { + std::cout << _irOpt << std::endl; + printErrors(std::cout, stackIrOpt.errors()); + yulAssert(false, "Compiler generated malformed optimized IR"); + } + + ostringstream os1; + ostringstream os2; + yulFuzzerUtil::interpret( + os1, + stackIr.parserResult()->code, + EVMDialect::strictAssemblyForEVMObjects(_version) + ); + + yulFuzzerUtil::TerminationReason termReason = yulFuzzerUtil::interpret( + os2, + stackIrOpt.parserResult()->code, + EVMDialect::strictAssemblyForEVMObjects(_version) + ); + + if (termReason == yulFuzzerUtil::TerminationReason::StepLimitReached) + return; + + bool isTraceEq = (os1.str() == os2.str()); + yulAssert(isTraceEq, "Interpreted traces for optimized and unoptimized code differ."); +} + void FuzzerUtil::testCompiler(StringMap& _input, bool _optimize, unsigned _rand, bool _forceSMT) { frontend::CompilerStack compiler; @@ -96,11 +184,23 @@ void FuzzerUtil::testCompiler(StringMap& _input, bool _optimize, unsigned _rand, compiler.setModelCheckerSettings({frontend::ModelCheckerEngine::All(), frontend::ModelCheckerTargets::All(), /*timeout=*/1}); } compiler.setSources(_input); + compiler.enableIRGeneration(); compiler.setEVMVersion(evmVersion); compiler.setOptimiserSettings(optimiserSettings); try { - compiler.compile(); + if (compiler.compile() && !compiler.contractNames().empty()) + { + string lastContractName = compiler.lastContractName(); + yulIRDiff( + evmVersion, + compiler.yulIR(lastContractName), + compiler.yulIROptimized(lastContractName) + ); + } + } + catch (InternalCompilerError const&) + { } catch (Error const&) { diff --git a/test/tools/fuzzer_common.h b/test/tools/fuzzer_common.h index de8d52f8f..4ba4ef346 100644 --- a/test/tools/fuzzer_common.h +++ b/test/tools/fuzzer_common.h @@ -18,6 +18,7 @@ #include +#include #include #include @@ -46,4 +47,5 @@ struct FuzzerUtil /// Adds the experimental SMTChecker pragma to each source file in the /// source map. static void forceSMT(solidity::StringMap& _input); + static void yulIRDiff(solidity::langutil::EVMVersion _version, std::string const& _ir, std::string const& _irOpt); }; diff --git a/test/tools/ossfuzz/CMakeLists.txt b/test/tools/ossfuzz/CMakeLists.txt index dbfdbf1a1..af3a90875 100644 --- a/test/tools/ossfuzz/CMakeLists.txt +++ b/test/tools/ossfuzz/CMakeLists.txt @@ -28,8 +28,13 @@ if (OSSFUZZ) solc_opt_ossfuzz.cpp ../fuzzer_common.cpp ../../TestCaseReader.cpp + yulFuzzerCommon.cpp ) - target_link_libraries(solc_opt_ossfuzz PRIVATE libsolc evmasm) + target_compile_options(solc_opt_ossfuzz + PUBLIC + ${COMPILE_OPTIONS} -Wno-extra-semi -Wno-unused-parameter + ) + target_link_libraries(solc_opt_ossfuzz PRIVATE libsolc evmasm yul yulInterpreter) set_target_properties(solc_opt_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) add_executable(solc_opt_mutator_ossfuzz @@ -46,8 +51,13 @@ if (OSSFUZZ) solc_noopt_ossfuzz.cpp ../fuzzer_common.cpp ../../TestCaseReader.cpp + yulFuzzerCommon.cpp ) - target_link_libraries(solc_noopt_ossfuzz PRIVATE libsolc evmasm) + target_compile_options(solc_noopt_ossfuzz + PUBLIC + ${COMPILE_OPTIONS} -Wno-extra-semi -Wno-unused-parameter + ) + target_link_libraries(solc_noopt_ossfuzz PRIVATE libsolc evmasm yul yulInterpreter) set_target_properties(solc_noopt_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) add_executable(solc_noopt_mutator_ossfuzz diff --git a/test/tools/ossfuzz/solc_opt_ossfuzz.cpp b/test/tools/ossfuzz/solc_opt_ossfuzz.cpp index fab83166d..2b96d244b 100644 --- a/test/tools/ossfuzz/solc_opt_ossfuzz.cpp +++ b/test/tools/ossfuzz/solc_opt_ossfuzz.cpp @@ -30,7 +30,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size); extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) { - if (_size <= 600) + if (_size <= 4096) { string input(reinterpret_cast(_data), _size); map sourceCode; diff --git a/test/tools/ossfuzz/yulFuzzerCommon.h b/test/tools/ossfuzz/yulFuzzerCommon.h index 489cc4532..52b254fe0 100644 --- a/test/tools/ossfuzz/yulFuzzerCommon.h +++ b/test/tools/ossfuzz/yulFuzzerCommon.h @@ -40,7 +40,7 @@ struct yulFuzzerUtil size_t _maxTraceSize = maxTraceSize, size_t _maxExprNesting = maxExprNesting ); - static size_t constexpr maxSteps = 100; + static size_t constexpr maxSteps = 10000000; static size_t constexpr maxTraceSize = 75; static size_t constexpr maxExprNesting = 64; };