Coverage Report

Created: 2026-10-24 08:16

/work/toxcore/group_announce_fuzz_test.cc
Line
Count
Source (jump to first uncovered line)
1
#include "group_announce.h"
2
3
#include <cassert>
4
#include <cstddef>
5
#include <functional>
6
#include <memory>
7
#include <vector>
8
9
#include "../testing/support/public/fuzz_data.hh"
10
#include "../testing/support/public/simulated_environment.hh"
11
#include "attributes.h"
12
13
namespace {
14
15
using tox::test::FakeClock;
16
using tox::test::Fuzz_Data;
17
using tox::test::SimulatedEnvironment;
18
19
void TestUnpackAnnouncesList(Fuzz_Data &input)
20
92
{
21
92
    CONSUME1_OR_RETURN(const std::uint8_t, max_count, input);
22
    // Always allocate at least something to avoid passing nullptr to functions below.
23
91
    std::vector<GC_Announce> announces(max_count + 1);
24
25
    // TODO(iphydf): How do we know the packed size?
26
91
    CONSUME1_OR_RETURN(const std::uint16_t, packed_size, input);
27
28
90
    SimulatedEnvironment env{12345};
29
90
    auto c_mem = env.fake_memory().c_memory();
30
90
    Logger *logger = logger_new(&c_mem);
31
90
    if (gca_unpack_announces_list(logger, input.data(), input.size(), announces.data(), max_count)
32
90
        != -1) {
33
        // Always allocate at least something to avoid passing nullptr to functions below.
34
55
        std::vector<std::uint8_t> packed(packed_size + 1);
35
55
        std::size_t processed;
36
55
        gca_pack_announces_list(
37
55
            logger, packed.data(), packed_size, announces.data(), max_count, &processed);
38
55
    }
39
90
    logger_kill(logger);
40
90
}
41
42
void TestUnpackPublicAnnounce(Fuzz_Data &input)
43
7
{
44
7
    GC_Public_Announce public_announce;
45
46
    // TODO(iphydf): How do we know the packed size?
47
7
    CONSUME1_OR_RETURN(const std::uint16_t, packed_size, input);
48
49
6
    SimulatedEnvironment env{12345};
50
6
    auto c_mem = env.fake_memory().c_memory();
51
6
    Logger *logger = logger_new(&c_mem);
52
6
    if (gca_unpack_public_announce(logger, input.data(), input.size(), &public_announce) != -1) {
53
        // Always allocate at least something to avoid passing nullptr to functions below.
54
3
        std::vector<std::uint8_t> packed(packed_size + 1);
55
3
        gca_pack_public_announce(logger, packed.data(), packed_size, &public_announce);
56
3
    }
57
6
    logger_kill(logger);
58
6
}
59
60
void TestDoGca(Fuzz_Data &input)
61
232
{
62
232
    SimulatedEnvironment env{12345};
63
232
    auto c_mem = env.fake_memory().c_memory();
64
232
    std::unique_ptr<Logger, void (*)(Logger *)> logger(logger_new(&c_mem), logger_kill);
65
66
232
    std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time(
67
232
        mono_time_new(
68
232
            &c_mem,
69
232
            [](void *_Nullable user_data) -> std::uint64_t {
70
232
                return static_cast<FakeClock *>(user_data)->current_time_ms();
71
232
            },
72
232
            &env.fake_clock()),
73
232
        [c_mem](Mono_Time *ptr) { mono_time_free(&c_mem, ptr); });
74
232
    assert(mono_time != nullptr);
75
76
232
    std::unique_ptr<GC_Announces_List, std::function<void(GC_Announces_List *)>> gca(
77
232
        new_gca_list(&c_mem), [](GC_Announces_List *ptr) { kill_gca(ptr); });
78
232
    assert(gca != nullptr);
79
80
4.31k
    while (!input.empty()) {
81
4.09k
        CONSUME1_OR_RETURN(const std::uint8_t, choice, input);
82
4.09k
        switch (choice) {
83
1.83k
        case 0: {
84
            // Add an announce.
85
1.83k
            CONSUME1_OR_RETURN(const std::uint16_t, length, input);
86
1.83k
            CONSUME_OR_RETURN(const std::uint8_t *data, input, length);
87
1.83k
            GC_Public_Announce public_announce;
88
1.83k
            if (gca_unpack_public_announce(logger.get(), data, length, &public_announce) != -1) {
89
719
                gca_add_announce(&c_mem, mono_time.get(), gca.get(), &public_announce);
90
719
            }
91
1.83k
            break;
92
1.83k
        }
93
369
        case 1: {
94
            // Advance the time by a number of tox_iteration_intervals.
95
369
            CONSUME1_OR_RETURN(const std::uint8_t, iterations, input);
96
368
            env.fake_clock().advance(iterations * 20);
97
            // Do an iteration.
98
368
            do_gca(mono_time.get(), gca.get());
99
368
            break;
100
369
        }
101
918
        case 2: {
102
            // Get announces.
103
918
            CONSUME1_OR_RETURN(const std::uint8_t, max_nodes, input);
104
            // Always allocate at least something to avoid passing nullptr to functions below.
105
917
            std::vector<GC_Announce> gc_announces(max_nodes + 1);
106
917
            CONSUME_OR_RETURN(const std::uint8_t *chat_id, input, CHAT_ID_SIZE);
107
910
            CONSUME_OR_RETURN(const std::uint8_t *except_public_key, input, ENC_PUBLIC_KEY_SIZE);
108
909
            gca_get_announces(
109
909
                gca.get(), gc_announces.data(), max_nodes, chat_id, except_public_key);
110
909
            break;
111
910
        }
112
641
        case 3: {
113
            // Remove a chat.
114
641
            CONSUME_OR_RETURN(const std::uint8_t *chat_id, input, CHAT_ID_SIZE);
115
640
            cleanup_gca(gca.get(), chat_id);
116
640
            break;
117
641
        }
118
4.09k
        }
119
4.09k
    }
120
232
}
121
122
}  // namespace
123
124
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size);
125
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size)
126
2.69k
{
127
2.69k
    tox::test::fuzz_select_target<TestUnpackAnnouncesList, TestUnpackPublicAnnounce, TestDoGca>(
128
2.69k
        data, size);
129
2.69k
    return 0;
130
2.69k
}