diff --git a/Makefile b/Makefile index 08c40d2f34..b45f8afb83 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ all: @echo "fuzz_testing_cbor - prepare fuzz testing of the CBOR parser" @echo "fuzz_testing_msgpack - prepare fuzz testing of the MessagePack parser" @echo "fuzz_testing_ubjson - prepare fuzz testing of the UBJSON parser" + @echo "fuzz_testing_stl - prepare fuzz testing of STL operators" @echo "json_unit - create single-file test executable" @echo "pedantic_clang - run Clang with maximal warning flags" @echo "pedantic_gcc - run GCC with maximal warning flags" @@ -402,6 +403,14 @@ fuzz_testing_ubjson: find test/data -size -5k -name *.ubjson | xargs -I{} cp "{}" fuzz-testing/testcases @echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer" +fuzz_testing_stl: + rm -fr fuzz-testing + mkdir -p fuzz-testing fuzz-testing/testcases fuzz-testing/out + $(MAKE) stl_operations_fuzzer -C test CXX=afl-clang++ + mv test/stl_operations_fuzzer fuzz-testing/fuzzer + find test/data -size -5k -name *.json | xargs -I{} cp "{}" fuzz-testing/testcases + @echo "Execute: afl-fuzz -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer" + fuzzing-start: afl-fuzz -S fuzzer1 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null & afl-fuzz -S fuzzer2 -i fuzz-testing/testcases -o fuzz-testing/out fuzz-testing/fuzzer > /dev/null & diff --git a/test/Makefile b/test/Makefile index 7bf0fef98b..9ea0d1fb4a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -94,7 +94,7 @@ check: $(OBJECTS) $(TESTCASES) ############################################################################## FUZZER_ENGINE = src/fuzzer-driver_afl.cpp -FUZZERS = parse_afl_fuzzer parse_bson_fuzzer parse_cbor_fuzzer parse_msgpack_fuzzer parse_ubjson_fuzzer +FUZZERS = parse_afl_fuzzer parse_bson_fuzzer parse_cbor_fuzzer parse_msgpack_fuzzer parse_ubjson_fuzzer stl_operations_fuzzer fuzzers: $(FUZZERS) parse_afl_fuzzer: @@ -111,3 +111,6 @@ parse_msgpack_fuzzer: parse_ubjson_fuzzer: $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-parse_ubjson.cpp -o $@ + +stl_operations_fuzzer: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-stl_operations.cpp -o $@ diff --git a/test/src/fuzzer-stl_operations.cpp b/test/src/fuzzer-stl_operations.cpp new file mode 100644 index 0000000000..93769495d5 --- /dev/null +++ b/test/src/fuzzer-stl_operations.cpp @@ -0,0 +1,140 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (fuzz test support) +| | |__ | | | | | | version 3.7.3 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +This file implements test for stl operations suitable for fuzz testing. + +The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer +drivers. + +Licensed under the MIT License . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using json = nlohmann::json; + +// see http://llvm.org/docs/LibFuzzer.html +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + // putting data in several STL containers + std::vector vec(data, data + size); + std::deque deq(data, data + size); + std::list lst(data, data + size); + std::forward_list flist(data, data + size); + std::set st(data, data + size); + std::unordered_set uset(data, data + size); + std::multiset multist(data, data + size); + std::unordered_multiset umultiset(data, data + size); + + // parsing from STL containers + json j_vector(vec); + json j_deque(deq); + json j_list(lst); + json j_flist(flist); + json j_set(st); + json j_uset(uset); + json j_multiset(multist); + json j_umultiset(umultiset); + + // json must be same for sequence containers + assert(j_vector == j_deque); + assert(j_vector == j_list); + assert(j_vector == j_flist); + + // iterating json array and testing get() method + for(json::iterator it = j_vector.begin(); it != j_vector.end(); ++it) + { + try + { + int temp = (*it).get(); + } + catch(const json::type_error) + { + // input might not be convertible to integer + } + } + + for(auto& element : j_vector) + { + // range-based iteration + } + + json j_vector2 = json::array(); + json j_vector3 = json::array(); + + for(std::size_t i = 0; i < j_vector.size(); ++i) + { + auto temp = j_vector.at(i); + // testing at() method + j_vector2.push_back(temp); + j_vector3.emplace_back(temp); + // testing push_back and emplace back methods + } + + // these three json vectors must be the same + assert(j_vector == j_vector2); + assert(j_vector == j_vector3); + + std::map mp; + std::unordered_map umap; + std::multimap multimp; + std::unordered_multimap umultimap; + + // converting each consecutive entry in the vector into a key-value pair and adding them to map + for(std::size_t i = 1; i < vec.size(); i+=2) + { + int last_entry = static_cast(vec[i-1]); + std::string key_str = std::to_string(last_entry); + std::pair insert_data = std::make_pair(key_str, vec[i]); + mp.insert(insert_data); + umap.insert(insert_data); + multimp.insert(insert_data); + umultimap.insert(insert_data); + } + + // map -> json map + json j_map(mp); + json j_umap(umap); + json j_multimap(multimp); + json j_umultimap(umultimap); + + // iterating json map + for(json::iterator it = j_map.begin(); it != j_map.end(); ++it) + { + auto temp1 = it.key(); + auto temp2 = it.value(); + } + + try + { + // parse input directly + json j1 = json::parse(data, data + size); + // parse using vector + json j_vec = json::parse(vec); + + // both of them must be equal + assert(j1 == j_vec); + } + catch (const json::parse_error&) + { + // parse errors are ok, because input may be random bytes + } + catch (const json::out_of_range&) + { + // out of range errors may happen if provided sizes are excessive + } + return 0; +}