Coverage Report

Created: 2025-08-03 07:06

/src/immer/extra/fuzzer/map-gc.cpp
Line
Count
Source (jump to first uncovered line)
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_gc_guard.hpp"
10
#include "fuzzer_input.hpp"
11
12
#include <immer/heap/gc_heap.hpp>
13
#include <immer/map.hpp>
14
#include <immer/refcount/no_refcount_policy.hpp>
15
16
#include <immer/algorithm.hpp>
17
18
#include <array>
19
20
using gc_memory = immer::memory_policy<immer::heap_policy<immer::gc_heap>,
21
                                       immer::no_refcount_policy,
22
                                       immer::default_lock_policy,
23
                                       immer::gc_transience_policy,
24
                                       false>;
25
26
struct colliding_hash_t
27
{
28
336k
    std::size_t operator()(std::size_t x) const { return x & ~15; }
29
};
30
31
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data,
32
                                      std::size_t size)
33
3.86k
{
34
3.86k
    auto guard = fuzzer_gc_guard{};
35
36
3.86k
    constexpr auto var_count = 4;
37
38
3.86k
    using map_t = immer::
39
3.86k
        map<std::size_t, int, colliding_hash_t, std::equal_to<>, gc_memory>;
40
41
3.86k
    auto vars = std::array<map_t, var_count>{};
42
43
321k
    auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; };
44
45
95.5k
    return fuzzer_input{data, size}.run([&](auto& in) {
46
95.5k
        enum ops
47
95.5k
        {
48
95.5k
            op_set,
49
95.5k
            op_erase,
50
95.5k
            op_set_move,
51
95.5k
            op_erase_move,
52
95.5k
            op_iterate,
53
95.5k
            op_find,
54
95.5k
            op_update,
55
95.5k
            op_update_move,
56
95.5k
            op_update_if_exists,
57
95.5k
            op_update_if_exists_move,
58
95.5k
            op_diff
59
95.5k
        };
60
95.5k
        auto src = read<char>(in, is_valid_var);
61
95.5k
        auto dst = read<char>(in, is_valid_var);
62
95.5k
        switch (read<char>(in)) {
63
42.3k
        case op_set: {
64
42.3k
            auto value = read<size_t>(in);
65
42.3k
            vars[dst]  = vars[src].set(value, 42);
66
42.3k
            break;
67
0
        }
68
5.20k
        case op_erase: {
69
5.20k
            auto value = read<size_t>(in);
70
5.20k
            vars[dst]  = vars[src].erase(value);
71
5.20k
            break;
72
0
        }
73
925
        case op_set_move: {
74
925
            auto value = read<size_t>(in);
75
925
            vars[dst]  = std::move(vars[src]).set(value, 42);
76
925
            break;
77
0
        }
78
1.16k
        case op_erase_move: {
79
1.16k
            auto value = read<size_t>(in);
80
1.16k
            vars[dst]  = std::move(vars[src]).erase(value);
81
1.16k
            break;
82
0
        }
83
6.17k
        case op_iterate: {
84
6.17k
            auto srcv = vars[src];
85
101k
            for (const auto& v : srcv) {
86
101k
                vars[dst] = vars[dst].set(v.first, v.second);
87
101k
            }
88
6.17k
            break;
89
0
        }
90
2.02k
        case op_find: {
91
2.02k
            auto value = read<size_t>(in);
92
2.02k
            auto res   = vars[src].find(value);
93
2.02k
            if (res != nullptr) {
94
826
                vars[dst] = vars[dst].set(*res, 42);
95
826
            }
96
2.02k
            break;
97
0
        }
98
2.60k
        case op_update: {
99
2.60k
            auto key  = read<size_t>(in);
100
2.60k
            vars[dst] = vars[src].update(key, [](int x) { return x + 1; });
101
2.60k
            break;
102
0
        }
103
2.01k
        case op_update_move: {
104
2.01k
            auto key = read<size_t>(in);
105
2.01k
            vars[dst] =
106
2.01k
                std::move(vars[src]).update(key, [](int x) { return x + 1; });
107
2.01k
            break;
108
0
        }
109
9.75k
        case op_update_if_exists: {
110
9.75k
            auto key = read<size_t>(in);
111
9.75k
            vars[dst] =
112
9.75k
                vars[src].update_if_exists(key, [](int x) { return x + 1; });
113
9.75k
            break;
114
0
        }
115
1.77k
        case op_update_if_exists_move: {
116
1.77k
            auto key  = read<size_t>(in);
117
1.77k
            vars[dst] = std::move(vars[src]).update_if_exists(
118
1.77k
                key, [](int x) { return x + 1; });
119
1.77k
            break;
120
0
        }
121
11.5k
        case op_diff: {
122
11.5k
            auto&& a = vars[src];
123
11.5k
            auto&& b = vars[dst];
124
11.5k
            diff(
125
11.5k
                a,
126
11.5k
                b,
127
39.9k
                [&](auto&& x) {
128
39.9k
                    assert(!a.count(x.first));
129
39.9k
                    assert(b.count(x.first));
130
39.9k
                },
131
33.9k
                [&](auto&& x) {
132
33.9k
                    assert(a.count(x.first));
133
33.9k
                    assert(!b.count(x.first));
134
33.9k
                },
135
11.5k
                [&](auto&& x, auto&& y) {
136
551
                    assert(x.first == y.first);
137
551
                    assert(x.second != y.second);
138
551
                });
139
11.5k
        }
140
17.8k
        default:
141
17.8k
            break;
142
95.5k
        };
143
91.7k
        return true;
144
95.5k
    });
145
3.86k
}