1//
2// immer: immutable data structures for C++
3// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
4//
5// This software is distributed under the Boost Software License, Version 1.0.
6// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
7//
8
9#include "fuzzer_input.hpp"
10#include <immer/box.hpp>
11#include <immer/flex_vector.hpp>
12#include <iostream>
13#include <array>
14
15extern "C"
16int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size)
17{
18 constexpr auto var_count = 8;
19 constexpr auto bits = 2;
20
21 using vector_t = immer::flex_vector<int, immer::default_memory_policy, bits, bits>;
22 using size_t = std::uint8_t;
23
24 auto vars = std::array<vector_t, var_count>{};
25
26 auto is_valid_var = [&] (auto idx) {
27 return idx >= 0 && idx < var_count;
28 };
29 auto is_valid_var_neq = [](auto other) {
30 return [=] (auto idx) {
31 return idx >= 0 && idx < var_count && idx != other;
32 };
33 };
34 auto is_valid_index = [] (auto& v) {
35 return [&] (auto idx) { return idx >= 0 && idx < v.size(); };
36 };
37 auto is_valid_size = [] (auto& v) {
38 return [&] (auto idx) { return idx >= 0 && idx <= v.size(); };
39 };
40 auto can_concat = [] (auto&& v1, auto&& v2) {
41 using size_type = decltype(v1.size());
42 auto max = std::numeric_limits<size_type>::max() >> (bits * 4);
43 return v1.size() < max && v2.size() < max;
44 };
45 return fuzzer_input{data, size}.run([&] (auto& in)
46 {
47 enum ops {
48 op_push_back,
49 op_update,
50 op_take,
51 op_drop,
52 op_concat,
53 op_push_back_move,
54 op_update_move,
55 op_take_move,
56 op_drop_move,
57 op_concat_move_l,
58 op_concat_move_r,
59 op_concat_move_lr,
60 op_insert,
61 op_erase,
62 op_compare,
63 };
64 auto src = read<char>(in, is_valid_var);
65 auto dst = read<char>(in, is_valid_var);
66 switch (read<char>(in))
67 {
68 case op_push_back: {
69 vars[dst] = vars[src].push_back(42);
70 break;
71 }
72 case op_update: {
73 auto idx = read<size_t>(in, is_valid_index(vars[src]));
74 vars[dst] = vars[src].update(idx, [] (auto x) { return x + 1; });
75 break;
76 }
77 case op_take: {
78 auto idx = read<size_t>(in, is_valid_size(vars[src]));
79 vars[dst] = vars[src].take(idx);
80 break;
81 }
82 case op_drop: {
83 auto idx = read<size_t>(in, is_valid_size(vars[src]));
84 vars[dst] = vars[src].drop(idx);
85 break;
86 }
87 case op_concat: {
88 auto src2 = read<char>(in, is_valid_var);
89 if (can_concat(vars[src], vars[src2]))
90 vars[dst] = vars[src] + vars[src2];
91 break;
92 }
93 case op_push_back_move: {
94 vars[dst] = std::move(vars[src]).push_back(21);
95 break;
96 }
97 case op_update_move: {
98 auto idx = read<size_t>(in, is_valid_index(vars[src]));
99 vars[dst] = std::move(vars[src])
100 .update(idx, [] (auto x) { return x + 1; });
101 break;
102 }
103 case op_take_move: {
104 auto idx = read<size_t>(in, is_valid_size(vars[src]));
105 vars[dst] = std::move(vars[src]).take(idx);
106 break;
107 }
108 case op_drop_move: {
109 auto idx = read<size_t>(in, is_valid_size(vars[src]));
110 vars[dst] = std::move(vars[src]).drop(idx);
111 break;
112 }
113 case op_concat_move_l: {
114 auto src2 = read<char>(in, is_valid_var_neq(src));
115 if (can_concat(vars[src], vars[src2]))
116 vars[dst] = std::move(vars[src]) + vars[src2];
117 break;
118 }
119 case op_concat_move_r: {
120 auto src2 = read<char>(in, is_valid_var_neq(src));
121 if (can_concat(vars[src], vars[src2]))
122 vars[dst] = vars[src] + std::move(vars[src2]);
123 break;
124 }
125 case op_concat_move_lr: {
126 auto src2 = read<char>(in, is_valid_var_neq(src));
127 if (can_concat(vars[src], vars[src2]))
128 vars[dst] = std::move(vars[src]) + std::move(vars[src2]);
129 }
130 case op_compare: {
131 using std::swap;
132 if (vars[src] == vars[dst])
133 swap(vars[src], vars[dst]);
134 break;
135 }
136 case op_erase: {
137 auto idx = read<size_t>(in, is_valid_index(vars[src]));
138 vars[dst] = vars[src].erase(idx);
139 break;
140 }
141 case op_insert: {
142 auto idx = read<size_t>(in, is_valid_size(vars[src]));
143 vars[dst] = vars[src].insert(idx, immer::box<int>{42});
144 break;
145 }
146 default:
147 break;
148 };
149 return true;
150 });
151}
152