diff options
Diffstat (limited to 'extra/fuzzer')
-rw-r--r-- | extra/fuzzer/CMakeLists.txt | 29 | ||||
-rw-r--r-- | extra/fuzzer/array-gc.cpp | 103 | ||||
-rw-r--r-- | extra/fuzzer/array.cpp | 80 | ||||
-rw-r--r-- | extra/fuzzer/flex-vector-gc.cpp | 162 | ||||
-rw-r--r-- | extra/fuzzer/flex-vector.cpp | 150 | ||||
-rw-r--r-- | extra/fuzzer/fuzzer_input.hpp | 62 | ||||
-rw-r--r-- | extra/fuzzer/map-gc.cpp | 93 | ||||
-rw-r--r-- | extra/fuzzer/map.cpp | 85 | ||||
-rw-r--r-- | extra/fuzzer/set-gc.cpp | 78 | ||||
-rw-r--r-- | extra/fuzzer/set.cpp | 70 | ||||
-rw-r--r-- | extra/fuzzer/vector-gc.cpp | 104 | ||||
-rw-r--r-- | extra/fuzzer/vector.cpp | 82 |
12 files changed, 1098 insertions, 0 deletions
diff --git a/extra/fuzzer/CMakeLists.txt b/extra/fuzzer/CMakeLists.txt new file mode 100644 index 000000000000..777289f8a12d --- /dev/null +++ b/extra/fuzzer/CMakeLists.txt @@ -0,0 +1,29 @@ + +add_custom_target(fuzzers + COMMENT "Build all fuzzers.") + +if (CHECK_FUZZERS) + add_dependencies(tests fuzzers) +endif() + +# LIB_FUZZING_ENGINE is set by the Google OSS-Fuzz +# infrastructure. Otherwise we use Clang's LibFuzzer +if (DEFINED ENV{LIB_FUZZING_ENGINE}) + set(immer_fuzzing_engine $ENV{LIB_FUZZING_ENGINE}) +else() + set(immer_fuzzing_engine "-fsanitize=fuzzer") +endif() + +file(GLOB_RECURSE immer_fuzzers "*.cpp") +foreach(_file IN LISTS immer_fuzzers) + immer_target_name_for(_target _output "${_file}") + add_executable(${_target} EXCLUDE_FROM_ALL "${_file}") + set_target_properties(${_target} PROPERTIES OUTPUT_NAME ${_output}) + target_compile_options(${_target} PUBLIC ${immer_fuzzing_engine}) + target_link_libraries(${_target} PUBLIC ${immer_fuzzing_engine} + immer-dev) + add_dependencies(fuzzers ${_target}) + if (CHECK_FUZZERS) + add_test("fuzzer/${_output}" ${_output} -max_total_time=1) + endif() +endforeach() diff --git a/extra/fuzzer/array-gc.cpp b/extra/fuzzer/array-gc.cpp new file mode 100644 index 000000000000..b93721225288 --- /dev/null +++ b/extra/fuzzer/array-gc.cpp @@ -0,0 +1,103 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#include "fuzzer_input.hpp" + +#include <immer/array.hpp> +#include <immer/array_transient.hpp> +#include <immer/heap/gc_heap.hpp> +#include <immer/refcount/no_refcount_policy.hpp> + +#include <array> + +using gc_memory = immer::memory_policy<immer::heap_policy<immer::gc_heap>, + immer::no_refcount_policy, + immer::gc_transience_policy, + false>; + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, + std::size_t size) +{ + constexpr auto var_count = 4; + + using array_t = immer::array<int, gc_memory>; + using transient_t = typename array_t::transient_type; + using size_t = std::uint8_t; + + auto vs = std::array<array_t, var_count>{}; + auto ts = std::array<transient_t, var_count>{}; + + auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; }; + auto is_valid_index = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx < v.size(); }; + }; + auto is_valid_size = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx <= v.size(); }; + }; + + return fuzzer_input{data, size}.run([&](auto& in) { + enum ops + { + op_transient, + op_persistent, + op_push_back, + op_update, + op_take, + op_push_back_mut, + op_update_mut, + op_take_mut, + }; + auto dst = read<char>(in, is_valid_var); + switch (read<char>(in)) { + case op_transient: { + auto src = read<char>(in, is_valid_var); + ts[dst] = vs[src].transient(); + break; + } + case op_persistent: { + auto src = read<char>(in, is_valid_var); + vs[dst] = ts[src].persistent(); + break; + } + case op_push_back: { + auto src = read<char>(in, is_valid_var); + vs[dst] = vs[src].push_back(42); + break; + } + case op_update: { + auto src = read<char>(in, is_valid_var); + auto idx = read<size_t>(in, is_valid_index(vs[src])); + vs[dst] = vs[src].update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take: { + auto src = read<char>(in, is_valid_var); + auto idx = read<size_t>(in, is_valid_size(vs[src])); + vs[dst] = vs[src].take(idx); + break; + } + case op_push_back_mut: { + ts[dst].push_back(13); + break; + } + case op_update_mut: { + auto idx = read<size_t>(in, is_valid_index(ts[dst])); + ts[dst].update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take_mut: { + auto idx = read<size_t>(in, is_valid_size(ts[dst])); + ts[dst].take(idx); + break; + } + default: + break; + }; + return true; + }); +} diff --git a/extra/fuzzer/array.cpp b/extra/fuzzer/array.cpp new file mode 100644 index 000000000000..094d97b7f425 --- /dev/null +++ b/extra/fuzzer/array.cpp @@ -0,0 +1,80 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#include "fuzzer_input.hpp" + +#include <immer/array.hpp> + +#include <array> + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, + std::size_t size) +{ + constexpr auto var_count = 4; + + using array_t = immer::array<int, immer::default_memory_policy>; + using size_t = std::uint8_t; + + auto vars = std::array<array_t, var_count>{}; + + auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; }; + auto is_valid_index = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx < v.size(); }; + }; + auto is_valid_size = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx <= v.size(); }; + }; + + return fuzzer_input{data, size}.run([&](auto& in) { + enum ops + { + op_push_back, + op_update, + op_take, + op_push_back_move, + op_update_move, + op_take_move, + }; + auto src = read<char>(in, is_valid_var); + auto dst = read<char>(in, is_valid_var); + switch (read<char>(in)) { + case op_push_back: { + vars[dst] = vars[src].push_back(42); + break; + } + case op_update: { + auto idx = read<size_t>(in, is_valid_index(vars[src])); + vars[dst] = vars[src].update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take: { + auto idx = read<size_t>(in, is_valid_size(vars[src])); + vars[dst] = vars[src].take(idx); + break; + } + case op_push_back_move: { + vars[dst] = std::move(vars[src]).push_back(12); + break; + } + case op_update_move: { + auto idx = read<size_t>(in, is_valid_index(vars[src])); + vars[dst] = + std::move(vars[src]).update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take_move: { + auto idx = read<size_t>(in, is_valid_size(vars[src])); + vars[dst] = std::move(vars[src]).take(idx); + break; + } + default: + break; + }; + return true; + }); +} diff --git a/extra/fuzzer/flex-vector-gc.cpp b/extra/fuzzer/flex-vector-gc.cpp new file mode 100644 index 000000000000..00c302898675 --- /dev/null +++ b/extra/fuzzer/flex-vector-gc.cpp @@ -0,0 +1,162 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#include "fuzzer_input.hpp" + +#include <immer/flex_vector.hpp> +#include <immer/flex_vector_transient.hpp> +#include <immer/heap/gc_heap.hpp> +#include <immer/refcount/no_refcount_policy.hpp> + +#include <array> + +using gc_memory = immer::memory_policy<immer::heap_policy<immer::gc_heap>, + immer::no_refcount_policy, + immer::gc_transience_policy, + false>; + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, + std::size_t size) +{ + constexpr auto var_count = 4; + constexpr auto bits = 2; + + using vector_t = immer::flex_vector<int, gc_memory, bits, bits>; + using transient_t = typename vector_t::transient_type; + using size_t = std::uint8_t; + + auto vs = std::array<vector_t, var_count>{}; + auto ts = std::array<transient_t, var_count>{}; + + auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; }; + auto is_valid_var_neq = [](auto other) { + return [=](auto idx) { + return idx >= 0 && idx < var_count && idx != other; + }; + }; + auto is_valid_index = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx < v.size(); }; + }; + auto is_valid_size = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx <= v.size(); }; + }; + auto can_concat = [](auto&& v1, auto&& v2) { + using size_type = decltype(v1.size()); + auto max = std::numeric_limits<size_type>::max() >> (bits * 4); + return v1.size() < max && v2.size() < max; + }; + + return fuzzer_input{data, size}.run([&](auto& in) { + enum ops + { + op_transient, + op_persistent, + op_push_back, + op_update, + op_take, + op_drop, + op_concat, + op_push_back_mut, + op_update_mut, + op_take_mut, + op_drop_mut, + op_prepend_mut, + op_prepend_mut_move, + op_append_mut, + op_append_mut_move, + }; + auto dst = read<char>(in, is_valid_var); + switch (read<char>(in)) { + case op_transient: { + auto src = read<char>(in, is_valid_var); + ts[dst] = vs[src].transient(); + break; + } + case op_persistent: { + auto src = read<char>(in, is_valid_var); + vs[dst] = ts[src].persistent(); + break; + } + case op_push_back: { + auto src = read<char>(in, is_valid_var); + vs[dst] = vs[src].push_back(42); + break; + } + case op_update: { + auto src = read<char>(in, is_valid_var); + auto idx = read<size_t>(in, is_valid_index(vs[src])); + vs[dst] = vs[src].update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take: { + auto src = read<char>(in, is_valid_var); + auto idx = read<size_t>(in, is_valid_size(vs[src])); + vs[dst] = vs[src].take(idx); + break; + } + case op_drop: { + auto src = read<char>(in, is_valid_var); + auto idx = read<size_t>(in, is_valid_size(vs[src])); + vs[dst] = vs[src].drop(idx); + break; + } + case op_concat: { + auto src = read<char>(in, is_valid_var); + auto src2 = read<char>(in, is_valid_var); + if (can_concat(vs[src], vs[src2])) + vs[dst] = vs[src] + vs[src2]; + break; + } + case op_push_back_mut: { + ts[dst].push_back(13); + break; + } + case op_update_mut: { + auto idx = read<size_t>(in, is_valid_index(ts[dst])); + ts[dst].update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take_mut: { + auto idx = read<size_t>(in, is_valid_size(ts[dst])); + ts[dst].take(idx); + break; + } + case op_prepend_mut: { + auto src = read<char>(in, is_valid_var_neq(dst)); + if (can_concat(ts[dst], ts[src])) + ts[dst].prepend(ts[src]); + break; + } + case op_prepend_mut_move: { + auto src = read<char>(in, is_valid_var_neq(dst)); + if (can_concat(ts[dst], ts[src])) { + ts[dst].prepend(std::move(ts[src])); + ts[src] = {}; + } + break; + } + case op_append_mut: { + auto src = read<char>(in, is_valid_var_neq(dst)); + if (can_concat(ts[dst], ts[src])) + ts[dst].append(ts[src]); + break; + } + case op_append_mut_move: { + auto src = read<char>(in, is_valid_var_neq(dst)); + if (can_concat(ts[dst], ts[src])) { + ts[dst].append(std::move(ts[src])); + ts[src] = {}; + } + break; + } + default: + break; + }; + return true; + }); +} diff --git a/extra/fuzzer/flex-vector.cpp b/extra/fuzzer/flex-vector.cpp new file mode 100644 index 000000000000..14395de1d5ae --- /dev/null +++ b/extra/fuzzer/flex-vector.cpp @@ -0,0 +1,150 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#include "fuzzer_input.hpp" + +#include <immer/box.hpp> +#include <immer/flex_vector.hpp> + +#include <array> + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, + std::size_t size) +{ + constexpr auto var_count = 8; + constexpr auto bits = 2; + + using vector_t = + immer::flex_vector<int, immer::default_memory_policy, bits, bits>; + using size_t = std::uint8_t; + + auto vars = std::array<vector_t, var_count>{}; + + auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; }; + auto is_valid_var_neq = [](auto other) { + return [=](auto idx) { + return idx >= 0 && idx < var_count && idx != other; + }; + }; + auto is_valid_index = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx < v.size(); }; + }; + auto is_valid_size = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx <= v.size(); }; + }; + auto can_concat = [](auto&& v1, auto&& v2) { + using size_type = decltype(v1.size()); + auto max = std::numeric_limits<size_type>::max() >> (bits * 4); + return v1.size() < max && v2.size() < max; + }; + return fuzzer_input{data, size}.run([&](auto& in) { + enum ops + { + op_push_back, + op_update, + op_take, + op_drop, + op_concat, + op_push_back_move, + op_update_move, + op_take_move, + op_drop_move, + op_concat_move_l, + op_concat_move_r, + op_concat_move_lr, + op_insert, + op_erase, + op_compare, + }; + auto src = read<char>(in, is_valid_var); + auto dst = read<char>(in, is_valid_var); + switch (read<char>(in)) { + case op_push_back: { + vars[dst] = vars[src].push_back(42); + break; + } + case op_update: { + auto idx = read<size_t>(in, is_valid_index(vars[src])); + vars[dst] = vars[src].update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take: { + auto idx = read<size_t>(in, is_valid_size(vars[src])); + vars[dst] = vars[src].take(idx); + break; + } + case op_drop: { + auto idx = read<size_t>(in, is_valid_size(vars[src])); + vars[dst] = vars[src].drop(idx); + break; + } + case op_concat: { + auto src2 = read<char>(in, is_valid_var); + if (can_concat(vars[src], vars[src2])) + vars[dst] = vars[src] + vars[src2]; + break; + } + case op_push_back_move: { + vars[dst] = std::move(vars[src]).push_back(21); + break; + } + case op_update_move: { + auto idx = read<size_t>(in, is_valid_index(vars[src])); + vars[dst] = + std::move(vars[src]).update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take_move: { + auto idx = read<size_t>(in, is_valid_size(vars[src])); + vars[dst] = std::move(vars[src]).take(idx); + break; + } + case op_drop_move: { + auto idx = read<size_t>(in, is_valid_size(vars[src])); + vars[dst] = std::move(vars[src]).drop(idx); + break; + } + case op_concat_move_l: { + auto src2 = read<char>(in, is_valid_var_neq(src)); + if (can_concat(vars[src], vars[src2])) + vars[dst] = std::move(vars[src]) + vars[src2]; + break; + } + case op_concat_move_r: { + auto src2 = read<char>(in, is_valid_var_neq(src)); + if (can_concat(vars[src], vars[src2])) + vars[dst] = vars[src] + std::move(vars[src2]); + break; + } + case op_concat_move_lr: { + auto src2 = read<char>(in, is_valid_var_neq(src)); + if (can_concat(vars[src], vars[src2])) + vars[dst] = std::move(vars[src]) + std::move(vars[src2]); + } + case op_compare: { + using std::swap; + if (vars[src] == vars[dst]) + swap(vars[src], vars[dst]); + break; + } + case op_erase: { + auto idx = read<size_t>(in, is_valid_index(vars[src])); + vars[dst] = vars[src].erase(idx); + break; + } + case op_insert: { + auto idx = read<size_t>(in, is_valid_size(vars[src])); + vars[dst] = vars[src].insert(idx, immer::box<int>{42}); + break; + } + default: + break; + }; + return true; + }); +} diff --git a/extra/fuzzer/fuzzer_input.hpp b/extra/fuzzer/fuzzer_input.hpp new file mode 100644 index 000000000000..485b7dc72b44 --- /dev/null +++ b/extra/fuzzer/fuzzer_input.hpp @@ -0,0 +1,62 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#pragma once + +#include <cstdint> +#include <stdexcept> + +struct no_more_input : std::exception +{}; + +struct fuzzer_input +{ + const std::uint8_t* data_; + std::size_t size_; + + const std::uint8_t* next(std::size_t size) + { + if (size_ < size) + throw no_more_input{}; + auto r = data_; + data_ += size; + size_ -= size; + return r; + } + + const std::uint8_t* next(std::size_t size, std::size_t align) + { + auto rem = size % align; + if (rem) + next(align - rem); + return next(size); + } + + template <typename Fn> + int run(Fn step) + { + try { + while (step(*this)) + continue; + } catch (const no_more_input&) {}; + return 0; + } +}; + +template <typename T> +const T& read(fuzzer_input& fz) +{ + return *reinterpret_cast<const T*>(fz.next(sizeof(T), alignof(T))); +} + +template <typename T, typename Cond> +T read(fuzzer_input& fz, Cond cond) +{ + auto x = read<T>(fz); + return cond(x) ? x : read<T>(fz, cond); +} diff --git a/extra/fuzzer/map-gc.cpp b/extra/fuzzer/map-gc.cpp new file mode 100644 index 000000000000..835f37a05897 --- /dev/null +++ b/extra/fuzzer/map-gc.cpp @@ -0,0 +1,93 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#include "fuzzer_input.hpp" + +#include <immer/heap/gc_heap.hpp> +#include <immer/map.hpp> +#include <immer/refcount/no_refcount_policy.hpp> + +#include <array> + +using gc_memory = immer::memory_policy<immer::heap_policy<immer::gc_heap>, + immer::no_refcount_policy, + immer::gc_transience_policy, + false>; + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, + std::size_t size) +{ + constexpr auto var_count = 4; + + using map_t = + immer::map<char, int, std::hash<char>, std::equal_to<char>, gc_memory>; + + auto vars = std::array<map_t, var_count>{}; + + auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; }; + + return fuzzer_input{data, size}.run([&](auto& in) { + enum ops + { + op_set, + op_erase, + op_set_move, + op_erase_move, + op_iterate, + op_find, + op_update + }; + auto src = read<char>(in, is_valid_var); + auto dst = read<char>(in, is_valid_var); + switch (read<char>(in)) { + case op_set: { + auto value = read<size_t>(in); + vars[dst] = vars[src].set(value, 42); + break; + } + case op_erase: { + auto value = read<size_t>(in); + vars[dst] = vars[src].erase(value); + break; + } + case op_set_move: { + auto value = read<size_t>(in); + vars[dst] = std::move(vars[src]).set(value, 42); + break; + } + case op_erase_move: { + auto value = read<size_t>(in); + vars[dst] = std::move(vars[src]).erase(value); + break; + } + case op_iterate: { + auto srcv = vars[src]; + for (const auto& v : srcv) { + vars[dst] = vars[dst].set(v.first, v.second); + } + break; + } + case op_find: { + auto value = read<size_t>(in); + auto res = vars[src].find(value); + if (res != nullptr) { + vars[dst] = vars[dst].set(*res, 42); + } + break; + } + case op_update: { + auto key = read<size_t>(in); + vars[dst] = vars[src].update(key, [](int x) { return x + 1; }); + break; + } + default: + break; + }; + return true; + }); +} diff --git a/extra/fuzzer/map.cpp b/extra/fuzzer/map.cpp new file mode 100644 index 000000000000..eb650679e932 --- /dev/null +++ b/extra/fuzzer/map.cpp @@ -0,0 +1,85 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#include "fuzzer_input.hpp" + +#include <immer/map.hpp> + +#include <array> + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, + std::size_t size) +{ + constexpr auto var_count = 4; + + using map_t = immer::map<char, int>; + + auto vars = std::array<map_t, var_count>{}; + + auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; }; + + return fuzzer_input{data, size}.run([&](auto& in) { + enum ops + { + op_set, + op_erase, + op_set_move, + op_erase_move, + op_iterate, + op_find, + op_update + }; + auto src = read<char>(in, is_valid_var); + auto dst = read<char>(in, is_valid_var); + switch (read<char>(in)) { + case op_set: { + auto value = read<size_t>(in); + vars[dst] = vars[src].set(value, 42); + break; + } + case op_erase: { + auto value = read<size_t>(in); + vars[dst] = vars[src].erase(value); + break; + } + case op_set_move: { + auto value = read<size_t>(in); + vars[dst] = std::move(vars[src]).set(value, 42); + break; + } + case op_erase_move: { + auto value = read<size_t>(in); + vars[dst] = std::move(vars[src]).erase(value); + break; + } + case op_iterate: { + auto srcv = vars[src]; + for (const auto& v : srcv) { + vars[dst] = vars[dst].set(v.first, v.second); + } + break; + } + case op_find: { + auto value = read<size_t>(in); + auto res = vars[src].find(value); + if (res != nullptr) { + vars[dst] = vars[dst].set(*res, 42); + } + break; + } + case op_update: { + auto key = read<size_t>(in); + vars[dst] = vars[src].update(key, [](int x) { return x + 1; }); + break; + } + default: + break; + }; + return true; + }); +} diff --git a/extra/fuzzer/set-gc.cpp b/extra/fuzzer/set-gc.cpp new file mode 100644 index 000000000000..3b88c08f3c2d --- /dev/null +++ b/extra/fuzzer/set-gc.cpp @@ -0,0 +1,78 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#include "fuzzer_input.hpp" + +#include <immer/heap/gc_heap.hpp> +#include <immer/refcount/no_refcount_policy.hpp> +#include <immer/set.hpp> + +#include <array> + +using gc_memory = immer::memory_policy<immer::heap_policy<immer::gc_heap>, + immer::no_refcount_policy, + immer::gc_transience_policy, + false>; + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, + std::size_t size) +{ + constexpr auto var_count = 4; + + using set_t = + immer::set<int, std::hash<char>, std::equal_to<char>, gc_memory>; + + auto vars = std::array<set_t, var_count>{}; + + auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; }; + + return fuzzer_input{data, size}.run([&](auto& in) { + enum ops + { + op_insert, + op_erase, + op_insert_move, + op_erase_move, + op_iterate + }; + auto src = read<char>(in, is_valid_var); + auto dst = read<char>(in, is_valid_var); + switch (read<char>(in)) { + case op_insert: { + auto value = read<size_t>(in); + vars[dst] = vars[src].insert(value); + break; + } + case op_erase: { + auto value = read<size_t>(in); + vars[dst] = vars[src].erase(value); + break; + } + case op_insert_move: { + auto value = read<size_t>(in); + vars[dst] = std::move(vars[src]).insert(value); + break; + } + case op_erase_move: { + auto value = read<size_t>(in); + vars[dst] = vars[src].erase(value); + break; + } + case op_iterate: { + auto srcv = vars[src]; + for (const auto& v : srcv) { + vars[dst] = vars[dst].insert(v); + } + break; + } + default: + break; + }; + return true; + }); +} diff --git a/extra/fuzzer/set.cpp b/extra/fuzzer/set.cpp new file mode 100644 index 000000000000..b25313d18cfc --- /dev/null +++ b/extra/fuzzer/set.cpp @@ -0,0 +1,70 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#include "fuzzer_input.hpp" + +#include <immer/set.hpp> + +#include <array> + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, + std::size_t size) +{ + constexpr auto var_count = 4; + + using set_t = immer::set<int>; + + auto vars = std::array<set_t, var_count>{}; + + auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; }; + + return fuzzer_input{data, size}.run([&](auto& in) { + enum ops + { + op_insert, + op_erase, + op_insert_move, + op_erase_move, + op_iterate + }; + auto src = read<char>(in, is_valid_var); + auto dst = read<char>(in, is_valid_var); + switch (read<char>(in)) { + case op_insert: { + auto value = read<size_t>(in); + vars[dst] = vars[src].insert(value); + break; + } + case op_erase: { + auto value = read<size_t>(in); + vars[dst] = vars[src].erase(value); + break; + } + case op_insert_move: { + auto value = read<size_t>(in); + vars[dst] = std::move(vars[src]).insert(value); + break; + } + case op_erase_move: { + auto value = read<size_t>(in); + vars[dst] = vars[src].erase(value); + break; + } + case op_iterate: { + auto srcv = vars[src]; + for (const auto& v : srcv) { + vars[dst] = vars[dst].insert(v); + } + break; + } + default: + break; + }; + return true; + }); +} diff --git a/extra/fuzzer/vector-gc.cpp b/extra/fuzzer/vector-gc.cpp new file mode 100644 index 000000000000..1faa729c5a72 --- /dev/null +++ b/extra/fuzzer/vector-gc.cpp @@ -0,0 +1,104 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#include "fuzzer_input.hpp" + +#include <immer/heap/gc_heap.hpp> +#include <immer/refcount/no_refcount_policy.hpp> +#include <immer/vector.hpp> +#include <immer/vector_transient.hpp> + +#include <array> + +using gc_memory = immer::memory_policy<immer::heap_policy<immer::gc_heap>, + immer::no_refcount_policy, + immer::gc_transience_policy, + false>; + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, + std::size_t size) +{ + constexpr auto var_count = 4; + constexpr auto bits = 2; + + using vector_t = immer::vector<int, gc_memory, bits, bits>; + using transient_t = typename vector_t::transient_type; + using size_t = std::uint8_t; + + auto vs = std::array<vector_t, var_count>{}; + auto ts = std::array<transient_t, var_count>{}; + + auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; }; + auto is_valid_index = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx < v.size(); }; + }; + auto is_valid_size = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx <= v.size(); }; + }; + + return fuzzer_input{data, size}.run([&](auto& in) { + enum ops + { + op_transient, + op_persistent, + op_push_back, + op_update, + op_take, + op_push_back_mut, + op_update_mut, + op_take_mut, + }; + auto dst = read<char>(in, is_valid_var); + switch (read<char>(in)) { + case op_transient: { + auto src = read<char>(in, is_valid_var); + ts[dst] = vs[src].transient(); + break; + } + case op_persistent: { + auto src = read<char>(in, is_valid_var); + vs[dst] = ts[src].persistent(); + break; + } + case op_push_back: { + auto src = read<char>(in, is_valid_var); + vs[dst] = vs[src].push_back(42); + break; + } + case op_update: { + auto src = read<char>(in, is_valid_var); + auto idx = read<size_t>(in, is_valid_index(vs[src])); + vs[dst] = vs[src].update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take: { + auto src = read<char>(in, is_valid_var); + auto idx = read<size_t>(in, is_valid_size(vs[src])); + vs[dst] = vs[src].take(idx); + break; + } + case op_push_back_mut: { + ts[dst].push_back(13); + break; + } + case op_update_mut: { + auto idx = read<size_t>(in, is_valid_index(ts[dst])); + ts[dst].update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take_mut: { + auto idx = read<size_t>(in, is_valid_size(ts[dst])); + ts[dst].take(idx); + break; + } + default: + break; + }; + return true; + }); +} diff --git a/extra/fuzzer/vector.cpp b/extra/fuzzer/vector.cpp new file mode 100644 index 000000000000..b04cbcee870c --- /dev/null +++ b/extra/fuzzer/vector.cpp @@ -0,0 +1,82 @@ +// +// immer: immutable data structures for C++ +// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente +// +// This software is distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt +// + +#include "fuzzer_input.hpp" + +#include <immer/vector.hpp> + +#include <array> + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, + std::size_t size) +{ + constexpr auto var_count = 4; + constexpr auto bits = 2; + + using vector_t = + immer::vector<int, immer::default_memory_policy, bits, bits>; + using size_t = std::uint8_t; + + auto vars = std::array<vector_t, var_count>{}; + + auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; }; + auto is_valid_index = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx < v.size(); }; + }; + auto is_valid_size = [](auto& v) { + return [&](auto idx) { return idx >= 0 && idx <= v.size(); }; + }; + + return fuzzer_input{data, size}.run([&](auto& in) { + enum ops + { + op_push_back, + op_update, + op_take, + op_push_back_move, + op_update_move, + op_take_move, + }; + auto src = read<char>(in, is_valid_var); + auto dst = read<char>(in, is_valid_var); + switch (read<char>(in)) { + case op_push_back: { + vars[dst] = vars[src].push_back(42); + break; + } + case op_update: { + auto idx = read<size_t>(in, is_valid_index(vars[src])); + vars[dst] = vars[src].update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take: { + auto idx = read<size_t>(in, is_valid_size(vars[src])); + vars[dst] = vars[src].take(idx); + break; + } + case op_push_back_move: { + vars[dst] = std::move(vars[src]).push_back(12); + break; + } + case op_update_move: { + auto idx = read<size_t>(in, is_valid_index(vars[src])); + vars[dst] = + std::move(vars[src]).update(idx, [](auto x) { return x + 1; }); + break; + } + case op_take_move: { + auto idx = read<size_t>(in, is_valid_size(vars[src])); + vars[dst] = std::move(vars[src]).take(idx); + break; + } + default: + break; + }; + return true; + }); +} |