Coverage Report

Created: 2025-11-09 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/immer/extra/fuzzer/map-gc.cpp
Line
Count
Source
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
4.73M
    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
86.7k
{
34
86.7k
    auto guard = fuzzer_gc_guard{};
35
36
86.7k
    constexpr auto var_count = 4;
37
38
86.7k
    using map_t = immer::
39
86.7k
        map<std::size_t, int, colliding_hash_t, std::equal_to<>, gc_memory>;
40
41
86.7k
    auto vars = std::array<map_t, var_count>{};
42
43
585k
    auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; };
44
45
167k
    return fuzzer_input{data, size}.run([&](auto& in) {
46
167k
        enum ops
47
167k
        {
48
167k
            op_set,
49
167k
            op_erase,
50
167k
            op_set_move,
51
167k
            op_erase_move,
52
167k
            op_iterate,
53
167k
            op_find,
54
167k
            op_update,
55
167k
            op_update_move,
56
167k
            op_update_if_exists,
57
167k
            op_update_if_exists_move,
58
167k
            op_diff
59
167k
        };
60
167k
        auto src = read<char>(in, is_valid_var);
61
167k
        auto dst = read<char>(in, is_valid_var);
62
167k
        switch (read<char>(in)) {
63
85.5k
        case op_set: {
64
85.5k
            auto value = read<size_t>(in);
65
85.5k
            vars[dst]  = vars[src].set(value, 42);
66
85.5k
            break;
67
0
        }
68
9.49k
        case op_erase: {
69
9.49k
            auto value = read<size_t>(in);
70
9.49k
            vars[dst]  = vars[src].erase(value);
71
9.49k
            break;
72
0
        }
73
1.52k
        case op_set_move: {
74
1.52k
            auto value = read<size_t>(in);
75
1.52k
            vars[dst]  = std::move(vars[src]).set(value, 42);
76
1.52k
            break;
77
0
        }
78
1.37k
        case op_erase_move: {
79
1.37k
            auto value = read<size_t>(in);
80
1.37k
            vars[dst]  = std::move(vars[src]).erase(value);
81
1.37k
            break;
82
0
        }
83
13.1k
        case op_iterate: {
84
13.1k
            auto srcv = vars[src];
85
503k
            for (const auto& v : srcv) {
86
503k
                vars[dst] = vars[dst].set(v.first, v.second);
87
503k
            }
88
13.1k
            break;
89
0
        }
90
2.86k
        case op_find: {
91
2.86k
            auto value = read<size_t>(in);
92
2.86k
            auto res   = vars[src].find(value);
93
2.86k
            if (res != nullptr) {
94
888
                vars[dst] = vars[dst].set(*res, 42);
95
888
            }
96
2.86k
            break;
97
0
        }
98
5.38k
        case op_update: {
99
5.38k
            auto key  = read<size_t>(in);
100
5.38k
            vars[dst] = vars[src].update(key, [](int x) { return x + 1; });
101
5.38k
            break;
102
0
        }
103
2.91k
        case op_update_move: {
104
2.91k
            auto key = read<size_t>(in);
105
2.91k
            vars[dst] =
106
2.91k
                std::move(vars[src]).update(key, [](int x) { return x + 1; });
107
2.91k
            break;
108
0
        }
109
11.1k
        case op_update_if_exists: {
110
11.1k
            auto key = read<size_t>(in);
111
11.1k
            vars[dst] =
112
11.1k
                vars[src].update_if_exists(key, [](int x) { return x + 1; });
113
11.1k
            break;
114
0
        }
115
2.78k
        case op_update_if_exists_move: {
116
2.78k
            auto key  = read<size_t>(in);
117
2.78k
            vars[dst] = std::move(vars[src]).update_if_exists(
118
2.78k
                key, [](int x) { return x + 1; });
119
2.78k
            break;
120
0
        }
121
14.5k
        case op_diff: {
122
14.5k
            auto&& a = vars[src];
123
14.5k
            auto&& b = vars[dst];
124
14.5k
            diff(
125
14.5k
                a,
126
14.5k
                b,
127
57.8k
                [&](auto&& x) {
128
57.8k
                    assert(!a.count(x.first));
129
57.8k
                    assert(b.count(x.first));
130
57.8k
                },
131
47.7k
                [&](auto&& x) {
132
47.7k
                    assert(a.count(x.first));
133
47.7k
                    assert(!b.count(x.first));
134
47.7k
                },
135
14.5k
                [&](auto&& x, auto&& y) {
136
1.29k
                    assert(x.first == y.first);
137
1.29k
                    assert(x.second != y.second);
138
1.29k
                });
139
14.5k
        }
140
27.5k
        default:
141
27.5k
            break;
142
167k
        };
143
163k
        return true;
144
167k
    });
145
86.7k
}