Coverage Report

Created: 2026-10-24 08:16

/work/testing/fuzzing/bootstrap_fuzz_test.cc
Line
Count
Source (jump to first uncovered line)
1
#include <cassert>
2
#include <cstddef>
3
#include <cstdio>
4
#include <functional>
5
#include <memory>
6
7
#include "../../toxcore/tox.h"
8
#include "../../toxcore/tox_dispatch.h"
9
#include "../../toxcore/tox_events.h"
10
#include "../../toxcore/tox_private.h"
11
#include "../support/public/fuzz_data.hh"
12
#include "../support/public/fuzz_helpers.hh"
13
#include "../support/public/simulated_environment.hh"
14
15
namespace {
16
17
using tox::test::configure_fuzz_memory_source;
18
using tox::test::configure_fuzz_packet_source;
19
using tox::test::FakeClock;
20
using tox::test::Fuzz_Data;
21
using tox::test::SimulatedEnvironment;
22
23
template <typename T>
24
using Ptr = std::unique_ptr<T, void (*)(T *)>;
25
26
void setup_callbacks(Tox_Dispatch *dispatch)
27
30
{
28
30
    tox_events_callback_conference_connected(
29
30
        dispatch, [](const Tox_Event_Conference_Connected *event, void *user_data) {
30
0
            assert(event == nullptr);
31
0
        });
32
30
    tox_events_callback_conference_connected(
33
30
        dispatch, [](const Tox_Event_Conference_Connected *event, void *user_data) {
34
0
            assert(event == nullptr);
35
0
        });
36
30
    tox_events_callback_conference_invite(
37
30
        dispatch, [](const Tox_Event_Conference_Invite *event, void *user_data) {
38
0
            assert(event == nullptr);
39
0
        });
40
30
    tox_events_callback_conference_message(
41
30
        dispatch, [](const Tox_Event_Conference_Message *event, void *user_data) {
42
0
            assert(event == nullptr);
43
0
        });
44
30
    tox_events_callback_conference_peer_list_changed(
45
30
        dispatch, [](const Tox_Event_Conference_Peer_List_Changed *event, void *user_data) {
46
0
            assert(event == nullptr);
47
0
        });
48
30
    tox_events_callback_conference_peer_name(
49
30
        dispatch, [](const Tox_Event_Conference_Peer_Name *event, void *user_data) {
50
0
            assert(event == nullptr);
51
0
        });
52
30
    tox_events_callback_conference_title(dispatch,
53
30
        [](const Tox_Event_Conference_Title *event, void *user_data) { assert(event == nullptr); });
54
30
    tox_events_callback_file_chunk_request(
55
30
        dispatch, [](const Tox_Event_File_Chunk_Request *event, void *user_data) {
56
0
            assert(event == nullptr);
57
0
        });
58
30
    tox_events_callback_file_recv(dispatch,
59
30
        [](const Tox_Event_File_Recv *event, void *user_data) { assert(event == nullptr); });
60
30
    tox_events_callback_file_recv_chunk(dispatch,
61
30
        [](const Tox_Event_File_Recv_Chunk *event, void *user_data) { assert(event == nullptr); });
62
30
    tox_events_callback_file_recv_control(
63
30
        dispatch, [](const Tox_Event_File_Recv_Control *event, void *user_data) {
64
0
            assert(event == nullptr);
65
0
        });
66
30
    tox_events_callback_friend_connection_status(
67
30
        dispatch, [](const Tox_Event_Friend_Connection_Status *event, void *user_data) {
68
0
            assert(event == nullptr);
69
0
        });
70
30
    tox_events_callback_friend_lossless_packet(
71
30
        dispatch, [](const Tox_Event_Friend_Lossless_Packet *event, void *user_data) {
72
0
            assert(event == nullptr);
73
0
        });
74
30
    tox_events_callback_friend_lossy_packet(
75
30
        dispatch, [](const Tox_Event_Friend_Lossy_Packet *event, void *user_data) {
76
0
            assert(event == nullptr);
77
0
        });
78
30
    tox_events_callback_friend_message(dispatch,
79
30
        [](const Tox_Event_Friend_Message *event, void *user_data) { assert(event == nullptr); });
80
30
    tox_events_callback_friend_name(dispatch,
81
30
        [](const Tox_Event_Friend_Name *event, void *user_data) { assert(event == nullptr); });
82
30
    tox_events_callback_friend_read_receipt(
83
30
        dispatch, [](const Tox_Event_Friend_Read_Receipt *event, void *user_data) {
84
0
            assert(event == nullptr);
85
0
        });
86
30
    tox_events_callback_friend_request(
87
30
        dispatch, [](const Tox_Event_Friend_Request *event, void *user_data) {
88
0
            Tox *tox = static_cast<Tox *>(user_data);
89
0
            Tox_Err_Friend_Add err;
90
0
            tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &err);
91
0
            if (!(err == TOX_ERR_FRIEND_ADD_OK || err == TOX_ERR_FRIEND_ADD_OWN_KEY
92
0
                    || err == TOX_ERR_FRIEND_ADD_ALREADY_SENT
93
0
                    || err == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM
94
0
                    || err == TOX_ERR_FRIEND_ADD_MALLOC)) {
95
0
                printf("unexpected error: %s\n", tox_err_friend_add_to_string(err));
96
0
            }
97
0
        });
98
30
    tox_events_callback_friend_status(dispatch,
99
30
        [](const Tox_Event_Friend_Status *event, void *user_data) { assert(event == nullptr); });
100
30
    tox_events_callback_friend_status_message(
101
30
        dispatch, [](const Tox_Event_Friend_Status_Message *event, void *user_data) {
102
0
            assert(event == nullptr);
103
0
        });
104
30
    tox_events_callback_friend_typing(dispatch,
105
30
        [](const Tox_Event_Friend_Typing *event, void *user_data) { assert(event == nullptr); });
106
30
    tox_events_callback_self_connection_status(
107
30
        dispatch, [](const Tox_Event_Self_Connection_Status *event, void *user_data) {
108
0
            assert(event == nullptr);
109
0
        });
110
30
}
111
112
void TestBootstrap(Fuzz_Data &input)
113
104
{
114
104
    SimulatedEnvironment env{12345};
115
104
    env.fake_clock().advance(1000000000);  // Match legacy behavior
116
104
    auto node = env.create_node(33445);
117
104
    configure_fuzz_memory_source(env.fake_memory(), input);
118
104
    configure_fuzz_packet_source(*node->endpoint, input);
119
120
    // Create a second null system for tox_events_equal check
121
104
    SimulatedEnvironment null_env{12346};
122
104
    auto null_node = null_env.create_node(0);  // Port 0 (unbound/irrelevant)
123
124
104
    Ptr<Tox_Options> opts(tox_options_new(nullptr), tox_options_free);
125
104
    assert(opts != nullptr);
126
127
104
    tox_options_set_log_callback(opts.get(),
128
104
        [](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
129
370
            const char *message, void *user_data) {
130
            // Log to stdout.
131
370
            if (Fuzz_Data::FUZZ_DEBUG) {
132
                // Approximate level name mapping
133
0
                char level_char = '?';
134
0
                switch (level) {
135
0
                case TOX_LOG_LEVEL_TRACE:
136
0
                    level_char = 'T';
137
0
                    break;
138
0
                case TOX_LOG_LEVEL_DEBUG:
139
0
                    level_char = 'D';
140
0
                    break;
141
0
                case TOX_LOG_LEVEL_INFO:
142
0
                    level_char = 'I';
143
0
                    break;
144
0
                case TOX_LOG_LEVEL_WARNING:
145
0
                    level_char = 'W';
146
0
                    break;
147
0
                case TOX_LOG_LEVEL_ERROR:
148
0
                    level_char = 'E';
149
0
                    break;
150
0
                }
151
0
                std::printf("[tox1] %c %s:%u(%s): %s\n", level_char, file, line, func, message);
152
0
            }
153
370
        });
154
155
104
    CONSUME1_OR_RETURN(const uint8_t, proxy_type, input);
156
104
    if (proxy_type == 0) {
157
6
        tox_options_set_proxy_type(opts.get(), TOX_PROXY_TYPE_NONE);
158
98
    } else if (proxy_type == 1) {
159
41
        tox_options_set_proxy_type(opts.get(), TOX_PROXY_TYPE_SOCKS5);
160
41
        tox_options_set_proxy_host(opts.get(), "127.0.0.1");
161
41
        tox_options_set_proxy_port(opts.get(), 8080);
162
57
    } else if (proxy_type == 2) {
163
33
        tox_options_set_proxy_type(opts.get(), TOX_PROXY_TYPE_HTTP);
164
33
        tox_options_set_proxy_host(opts.get(), "127.0.0.1");
165
33
        tox_options_set_proxy_port(opts.get(), 8080);
166
33
    }
167
168
104
    CONSUME1_OR_RETURN(const uint8_t, tcp_relay_enabled, input);
169
100
    if (tcp_relay_enabled >= (UINT8_MAX / 2)) {
170
43
        tox_options_set_tcp_port(opts.get(), 33445);
171
43
    }
172
173
100
    Tox_Options_Testing tox_options_testing;
174
100
    tox_options_testing.operating_system = &node->system;
175
176
100
    Tox_Err_New error_new;
177
100
    Tox_Err_New_Testing error_new_testing;
178
100
    Tox *tox = tox_new_testing(opts.get(), &error_new, &tox_options_testing, &error_new_testing);
179
180
100
    if (tox == nullptr) {
181
        // It might fail, because some I/O happens in tox_new, and the fuzzer
182
        // might do things that make that I/O fail.
183
70
        return;
184
70
    }
185
186
30
    assert(error_new == TOX_ERR_NEW_OK);
187
30
    assert(error_new_testing == TOX_ERR_NEW_TESTING_OK);
188
189
30
    uint8_t pub_key[TOX_PUBLIC_KEY_SIZE] = {0};
190
191
    // These may fail, but that's ok. We ignore their return values.
192
30
    tox_bootstrap(tox, "127.0.0.2", 33446, pub_key, nullptr);
193
30
    tox_add_tcp_relay(tox, "127.0.0.2", 33446, pub_key, nullptr);
194
195
30
    tox_events_init(tox);
196
197
30
    Tox_Dispatch *dispatch = tox_dispatch_new(nullptr);
198
30
    assert(dispatch != nullptr);
199
30
    setup_callbacks(dispatch);
200
201
30
    Ptr<Tox_Iterate_Options> iterate_opts(
202
30
        tox_iterate_options_new(nullptr), tox_iterate_options_free);
203
30
    tox_iterate_options_set_fail_hard(iterate_opts.get(), true);
204
205
30
    std::size_t input_size = input.size();
206
30
    while (!input.empty()) {
207
11
        Tox_Err_Events_Iterate error_iterate;
208
11
        Tox_Events *events = tox_events_iterate(tox, iterate_opts.get(), &error_iterate);
209
11
        assert(tox_events_equal(&null_node->system, events, events));
210
11
        tox_dispatch_invoke(dispatch, events, tox);
211
11
        tox_events_free(events);
212
213
11
        env.advance_time(200);
214
215
        // If no input was consumed, stop.
216
11
        if (input_size == input.size()) {
217
11
            break;
218
11
        }
219
220
0
        input_size = input.size();
221
0
    }
222
223
30
    tox_dispatch_free(dispatch);
224
30
    tox_kill(tox);
225
30
}
226
227
}
228
229
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, std::size_t size);
230
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, std::size_t size)
231
2.69k
{
232
2.69k
    Fuzz_Data input{data, size};
233
2.69k
    TestBootstrap(input);
234
2.69k
    return 0;  // Non-zero return values are reserved for future use.
235
2.69k
}