diff --git a/test/tools/ossfuzz/CMakeLists.txt b/test/tools/ossfuzz/CMakeLists.txt index a799bd736..622146209 100644 --- a/test/tools/ossfuzz/CMakeLists.txt +++ b/test/tools/ossfuzz/CMakeLists.txt @@ -27,7 +27,12 @@ if (OSSFUZZ) target_link_libraries(solc_opt_ossfuzz PRIVATE libsolc evmasm) set_target_properties(solc_opt_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) - add_executable(solc_noopt_ossfuzz solc_noopt_ossfuzz.cpp ../fuzzer_common.cpp ../../TestCaseReader.cpp) + add_executable(solc_noopt_ossfuzz + solc_noopt_ossfuzz.cpp + ../fuzzer_common.cpp + ../../TestCaseReader.cpp + SolRegexpMutator.cpp + ) target_link_libraries(solc_noopt_ossfuzz PRIVATE libsolc evmasm) set_target_properties(solc_noopt_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE}) diff --git a/test/tools/ossfuzz/SolRegexpMutator.cpp b/test/tools/ossfuzz/SolRegexpMutator.cpp new file mode 100644 index 000000000..23059cc38 --- /dev/null +++ b/test/tools/ossfuzz/SolRegexpMutator.cpp @@ -0,0 +1,43 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#include + +#include + +using namespace solidity::test::fuzzer; +using namespace std; + +size_t SRM::mutateInPlace(uint8_t* _data, size_t _size, size_t _maxSize, unsigned _ruleIdx) +{ + unsigned Idx = _ruleIdx % RegexpRules.size(); + string mutant = regex_replace( + string(_data, _data + _size), + RegexpRules[Idx].first, + RegexpRules[Idx].second, + regex_constants::format_first_only + ); + + if (mutant.size() < _maxSize) + { + mempcpy(_data, mutant.data(), mutant.size()); + return mutant.size(); + } + else + return 0; +} + diff --git a/test/tools/ossfuzz/SolRegexpMutator.h b/test/tools/ossfuzz/SolRegexpMutator.h new file mode 100644 index 000000000..9765867f9 --- /dev/null +++ b/test/tools/ossfuzz/SolRegexpMutator.h @@ -0,0 +1,54 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ + +#pragma once + +#include +#include +#include + +namespace solidity::test::fuzzer +{ + static std::vector> Mutations = { + {"==", "!="}, + {"!=", "=="}, + {">", "<="}, + {"<", ">="}, + {"<=", ">"}, + {">=", "<"}, + {"\n", "\nbreak;\n"}, + {"break;\n", ""}, + {"\n", "\ncontinue;\n"}, + {"continue;\n", ""} + }; + + struct SRM { + SRM() { + for (auto const& item: Mutations) + addRule(item.first, item.second); + } + + void addRule(std::string const& _pattern, std::string const& _replaceString) + { + RegexpRules.emplace_back(std::pair(std::regex(_pattern), _replaceString)); + } + + size_t mutateInPlace(uint8_t* _data, size_t size, size_t _maxSize, unsigned _ruleIdx); + + std::vector> RegexpRules = {}; + }; +} \ No newline at end of file diff --git a/test/tools/ossfuzz/solc_noopt_ossfuzz.cpp b/test/tools/ossfuzz/solc_noopt_ossfuzz.cpp index 8a7b83561..65c031c41 100644 --- a/test/tools/ossfuzz/solc_noopt_ossfuzz.cpp +++ b/test/tools/ossfuzz/solc_noopt_ossfuzz.cpp @@ -19,6 +19,8 @@ #include +#include + #include #include @@ -28,6 +30,7 @@ #include #include +using namespace solidity::test::fuzzer; using namespace solidity::frontend::test; using namespace std; @@ -39,8 +42,8 @@ struct CustomMutator { explicit CustomMutator(unsigned _seed = 1337): Rand(_seed) {} enum class Mutation { - DEFAULT, ADDSTMT, + MUTATE, NUMMUTATIONS }; @@ -61,15 +64,24 @@ struct CustomMutator { switch (_mut) { - case Mutation::DEFAULT: - return LLVMFuzzerMutate(_data, _size, _maxSize); case Mutation::ADDSTMT: return addStmt(_data, _size, _maxSize); + case Mutation::MUTATE: + return mutate(_data, _size, _maxSize); case Mutation::NUMMUTATIONS: solAssert(false, "Solc fuzzer: Invalid mutation selected"); } } + size_t mutate(uint8_t* _data, size_t _size, size_t _maxSize) + { + unsigned newSize = SRM{}.mutateInPlace(_data, _size, _maxSize, Rand()); + if (newSize == 0) + return LLVMFuzzerMutate(_data, _size, _maxSize); + else + return newSize; + } + size_t addStmt(uint8_t* _data, size_t _size, size_t _maxSize) { // Pseudo randomly choose statement