1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
//
// 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>
using st_memory = immer::memory_policy<immer::heap_policy<immer::cpp_heap>,
immer::unsafe_refcount_policy,
immer::no_lock_policy,
immer::no_transience_policy,
false>;
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data,
std::size_t size)
{
constexpr auto var_count = 8;
constexpr auto bits = 3;
using vector_t = immer::flex_vector<int, st_memory, 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 = [](const auto& v1, const auto& v2) {
// First, check max_size
if (v1.size() + v2.size() > vector_t::max_size()) {
return false;
}
// But just checking max_size is not sufficient, because there are other
// conditions for the validity of the tree, like shift constraints, for
// example.
try {
// Try to concat and catch an exception if it fails
const auto v3 = v1 + v2;
if (v3.size()) {
return true;
}
} catch (const immer::detail::rbts::invalid_tree&) {
return false;
}
return true;
};
auto can_compare = [](auto&& v) {
// avoid comparing vectors that are too big, and hence, slow to compare
return v.size() < (1 << 15);
};
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]);
break;
}
case op_compare: {
using std::swap;
if (can_compare(vars[src]) && 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;
});
}
|