Coverage Report

Created: 2025-08-25 06:16

/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
3.31M
    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.9k
{
34
86.9k
    auto guard = fuzzer_gc_guard{};
35
36
86.9k
    constexpr auto var_count = 4;
37
38
86.9k
    using map_t = immer::
39
86.9k
        map<std::size_t, int, colliding_hash_t, std::equal_to<>, gc_memory>;
40
41
86.9k
    auto vars = std::array<map_t, var_count>{};
42
43
310k
    auto is_valid_var = [&](auto idx) { return idx >= 0 && idx < var_count; };
44
45
94.4k
    return fuzzer_input{data, size}.run([&](auto& in) {
46
94.4k
        enum ops
47
94.4k
        {
48
94.4k
            op_set,
49
94.4k
            op_erase,
50
94.4k
            op_set_move,
51
94.4k
            op_erase_move,
52
94.4k
            op_iterate,
53
94.4k
            op_find,
54
94.4k
            op_update,
55
94.4k
            op_update_move,
56
94.4k
            op_update_if_exists,
57
94.4k
            op_update_if_exists_move,
58
94.4k
            op_diff
59
94.4k
        };
60
94.4k
        auto src = read<char>(in, is_valid_var);
61
94.4k
        auto dst = read<char>(in, is_valid_var);
62
94.4k
        switch (read<char>(in)) {
63
42.2k
        case op_set: {
64
42.2k
            auto value = read<size_t>(in);
65
42.2k
            vars[dst]  = vars[src].set(value, 42);
66
42.2k
            break;
67
0
        }
68
4.92k
        case op_erase: {
69
4.92k
            auto value = read<size_t>(in);
70
4.92k
            vars[dst]  = vars[src].erase(value);
71
4.92k
            break;
72
0
        }
73
885
        case op_set_move: {
74
885
            auto value = read<size_t>(in);
75
885
            vars[dst]  = std::move(vars[src]).set(value, 42);
76
885
            break;
77
0
        }
78
1.20k
        case op_erase_move: {
79
1.20k
            auto value = read<size_t>(in);
80
1.20k
            vars[dst]  = std::move(vars[src]).erase(value);
81
1.20k
            break;
82
0
        }
83
6.21k
        case op_iterate: {
84
6.21k
            auto srcv = vars[src];
85
100k
            for (const auto& v : srcv) {
86
100k
                vars[dst] = vars[dst].set(v.first, v.second);
87
100k
            }
88
6.21k
            break;
89
0
        }
90
1.90k
        case op_find: {
91
1.90k
            auto value = read<size_t>(in);
92
1.90k
            auto res   = vars[src].find(value);
93
1.90k
            if (res != nullptr) {
94
692
                vars[dst] = vars[dst].set(*res, 42);
95
692
            }
96
1.90k
            break;
97
0
        }
98
2.68k
        case op_update: {
99
2.68k
            auto key  = read<size_t>(in);
100
2.68k
            vars[dst] = vars[src].update(key, [](int x) { return x + 1; });
101
2.68k
            break;
102
0
        }
103
2.00k
        case op_update_move: {
104
2.00k
            auto key = read<size_t>(in);
105
2.00k
            vars[dst] =
106
2.00k
                std::move(vars[src]).update(key, [](int x) { return x + 1; });
107
2.00k
            break;
108
0
        }
109
9.86k
        case op_update_if_exists: {
110
9.86k
            auto key = read<size_t>(in);
111
9.86k
            vars[dst] =
112
9.86k
                vars[src].update_if_exists(key, [](int x) { return x + 1; });
113
9.86k
            break;
114
0
        }
115
1.78k
        case op_update_if_exists_move: {
116
1.78k
            auto key  = read<size_t>(in);
117
1.78k
            vars[dst] = std::move(vars[src]).update_if_exists(
118
1.78k
                key, [](int x) { return x + 1; });
119
1.78k
            break;
120
0
        }
121
11.1k
        case op_diff: {
122
11.1k
            auto&& a = vars[src];
123
11.1k
            auto&& b = vars[dst];
124
11.1k
            diff(
125
11.1k
                a,
126
11.1k
                b,
127
38.4k
                [&](auto&& x) {
128
38.4k
                    assert(!a.count(x.first));
129
38.4k
                    assert(b.count(x.first));
130
38.4k
                },
131
32.4k
                [&](auto&& x) {
132
32.4k
                    assert(a.count(x.first));
133
32.4k
                    assert(!b.count(x.first));
134
32.4k
                },
135
11.1k
                [&](auto&& x, auto&& y) {
136
461
                    assert(x.first == y.first);
137
461
                    assert(x.second != y.second);
138
461
                });
139
11.1k
        }
140
17.0k
        default:
141
17.0k
            break;
142
94.4k
        };
143
90.6k
        return true;
144
94.4k
    });
145
86.9k
}