Merge commit 'b1fe0644843f5d08cd203bb5d4cdb923172f247b'
This commit is contained in:
		@@ -1,6 +1,6 @@
 | 
			
		||||
#!/bin/bash -eu
 | 
			
		||||
 | 
			
		||||
FUZZ_TARGETS="bootstrap_fuzzer toxsave_fuzzer"
 | 
			
		||||
FUZZ_TARGETS="bootstrap_fuzz_test toxsave_fuzz_test"
 | 
			
		||||
 | 
			
		||||
# out of tree build
 | 
			
		||||
cd "$WORK"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								external/toxcore/c-toxcore/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								external/toxcore/c-toxcore/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							@@ -501,6 +501,8 @@ add_library(test_util STATIC
 | 
			
		||||
  toxcore/DHT_test_util.hh
 | 
			
		||||
  toxcore/crypto_core_test_util.cc
 | 
			
		||||
  toxcore/crypto_core_test_util.hh
 | 
			
		||||
  toxcore/mem_test_util.cc
 | 
			
		||||
  toxcore/mem_test_util.hh
 | 
			
		||||
  toxcore/network_test_util.cc
 | 
			
		||||
  toxcore/network_test_util.hh
 | 
			
		||||
  toxcore/test_util.cc
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
08fe68095b88c142e0c7f3369c5f297f1377e219d0e0f0ff6f30ca94d76fca98  /usr/local/bin/tox-bootstrapd
 | 
			
		||||
5061f92a95ba45cfa49d78175fa8fb6e4d66a58d86634ea3fd3ae6d80cb0558a  /usr/local/bin/tox-bootstrapd
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,4 @@
 | 
			
		||||
cd ../
 | 
			
		||||
 | 
			
		||||
# Run code coverage only on minized corpus to save time
 | 
			
		||||
afl-cov --cover-corpus -d ./_afl_out --overwrite --live --coverage-cmd "_cov_build/bootstrap_fuzzer @@" --code-dir ../
 | 
			
		||||
afl-cov --cover-corpus -d ./_afl_out --overwrite --live --coverage-cmd "_cov_build/bootstrap_fuzz_test @@" --code-dir ../
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
HARNESS_BIN="../_afl_build/bootstrap_fuzzer"
 | 
			
		||||
COV_BIN="../_cov_build/bootstrap_fuzzer"
 | 
			
		||||
HARNESS_BIN="../_afl_build/bootstrap_fuzz_test"
 | 
			
		||||
COV_BIN="../_cov_build/bootstrap_fuzz_test"
 | 
			
		||||
# move to repo root
 | 
			
		||||
cd ../
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
 | 
			
		||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
 | 
			
		||||
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test")
 | 
			
		||||
load("@rules_fuzzing//fuzzing/private:binary.bzl", "fuzzing_binary")  # buildifier: disable=bzl-visibility
 | 
			
		||||
 | 
			
		||||
cc_library(
 | 
			
		||||
    name = "fuzz_support",
 | 
			
		||||
@@ -27,9 +26,9 @@ cc_library(
 | 
			
		||||
cc_fuzz_test(
 | 
			
		||||
    name = "bootstrap_fuzz_test",
 | 
			
		||||
    size = "small",
 | 
			
		||||
    srcs = ["bootstrap_harness.cc"],
 | 
			
		||||
    srcs = ["bootstrap_fuzz_test.cc"],
 | 
			
		||||
    copts = ["-UNDEBUG"],
 | 
			
		||||
    corpus = ["//tools/toktok-fuzzer/corpus:bootstrap_fuzzer"],
 | 
			
		||||
    corpus = ["//tools/toktok-fuzzer/corpus:bootstrap_fuzz_test"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":fuzz_support",
 | 
			
		||||
        ":fuzz_tox",
 | 
			
		||||
@@ -58,9 +57,9 @@ cc_fuzz_test(
 | 
			
		||||
cc_fuzz_test(
 | 
			
		||||
    name = "toxsave_fuzz_test",
 | 
			
		||||
    size = "small",
 | 
			
		||||
    srcs = ["toxsave_harness.cc"],
 | 
			
		||||
    srcs = ["toxsave_fuzz_test.cc"],
 | 
			
		||||
    copts = ["-UNDEBUG"],
 | 
			
		||||
    corpus = ["//tools/toktok-fuzzer/corpus:toxsave_fuzzer"],
 | 
			
		||||
    corpus = ["//tools/toktok-fuzzer/corpus:toxsave_fuzz_test"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":fuzz_support",
 | 
			
		||||
        "//c-toxcore/toxcore:tox",
 | 
			
		||||
@@ -80,12 +79,34 @@ cc_binary(
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
fuzzing_binary(
 | 
			
		||||
    name = "protodump_bin",
 | 
			
		||||
    testonly = True,
 | 
			
		||||
    binary = ":protodump",
 | 
			
		||||
    engine = "@rules_fuzzing//fuzzing:cc_engine",
 | 
			
		||||
genrule(
 | 
			
		||||
    name = "e2e_fuzz_test_init",
 | 
			
		||||
    outs = [
 | 
			
		||||
        "e2e_fuzz_test_init.dat",
 | 
			
		||||
        "e2e_fuzz_test_bootstrap.dat",
 | 
			
		||||
    ],
 | 
			
		||||
    cmd = "$(location :protodump) $(location e2e_fuzz_test_init.dat) $(location e2e_fuzz_test_bootstrap.dat)",
 | 
			
		||||
    tags = ["manual"],
 | 
			
		||||
    tools = [":protodump"],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# bazel test --config=asan-libfuzzer //c-toxcore/testing/fuzzing:protodump_reduce_test
 | 
			
		||||
cc_test(
 | 
			
		||||
    name = "protodump_reduce_test",
 | 
			
		||||
    size = "small",
 | 
			
		||||
    srcs = ["protodump_reduce.cc"],
 | 
			
		||||
    args = ["$(location :e2e_fuzz_test_init.dat)"],
 | 
			
		||||
    copts = ["-UNDEBUG"],
 | 
			
		||||
    data = [":e2e_fuzz_test_init.dat"],
 | 
			
		||||
    tags = ["manual"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":fuzz_support",
 | 
			
		||||
        ":fuzz_tox",
 | 
			
		||||
        "//c-toxcore/toxcore:tox",
 | 
			
		||||
        "//c-toxcore/toxcore:tox_dispatch",
 | 
			
		||||
        "//c-toxcore/toxcore:tox_events",
 | 
			
		||||
        "@rules_fuzzing//fuzzing:cc_engine",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
cc_fuzz_test(
 | 
			
		||||
 
 | 
			
		||||
@@ -9,22 +9,18 @@ else()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
function(fuzz_test target source_dir)
 | 
			
		||||
  set(${target}_CORPUS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/toktok-fuzzer/corpus/${target}_fuzz_test)
 | 
			
		||||
  file(GLOB ${target}_fuzz_CORPUS "${${target}_CORPUS_DIR}/*")
 | 
			
		||||
  set(CORPUS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/toktok-fuzzer/corpus/${target}_fuzz_test)
 | 
			
		||||
  file(GLOB CORPUS "${CORPUS_DIR}/*")
 | 
			
		||||
  add_executable(${target}_fuzz_test ${source_dir}/${target}_fuzz_test.cc)
 | 
			
		||||
  target_link_libraries(${target}_fuzz_test PRIVATE toxcore_fuzz fuzz_support ${LIBFUZZER_LINKER_FLAGS})
 | 
			
		||||
  if(${target}_fuzz_CORPUS)
 | 
			
		||||
    add_test(NAME ${target}_fuzz COMMAND ${CROSSCOMPILING_EMULATOR} ${target}_fuzz_test -max_total_time=10 ${${target}_fuzz_CORPUS})
 | 
			
		||||
  target_link_libraries(${target}_fuzz_test PRIVATE fuzz_support test_util toxcore_fuzz ${LIBFUZZER_LINKER_FLAGS})
 | 
			
		||||
  if(CORPUS)
 | 
			
		||||
    add_test(NAME ${target}_fuzz COMMAND ${CROSSCOMPILING_EMULATOR} ${target}_fuzz_test -max_total_time=10 ${CORPUS})
 | 
			
		||||
    set_property(TEST ${target}_fuzz PROPERTY ENVIRONMENT "LLVM_PROFILE_FILE=${target}.profraw;srcdir=${CMAKE_CURRENT_SOURCE_DIR}")
 | 
			
		||||
  endif()
 | 
			
		||||
endfunction()
 | 
			
		||||
 | 
			
		||||
# Fuzzes the toxsave API
 | 
			
		||||
add_executable(toxsave_fuzzer toxsave_harness.cc)
 | 
			
		||||
target_link_libraries(toxsave_fuzzer PRIVATE toxcore_fuzz fuzz_support ${LIBFUZZER_LINKER_FLAGS})
 | 
			
		||||
 | 
			
		||||
# Fuzzes the bootstrap process
 | 
			
		||||
add_executable(bootstrap_fuzzer bootstrap_harness.cc)
 | 
			
		||||
target_link_libraries(bootstrap_fuzzer PRIVATE toxcore_fuzz fuzz_support ${LIBFUZZER_LINKER_FLAGS})
 | 
			
		||||
fuzz_test(bootstrap        .)  # Fuzzes the bootstrap process
 | 
			
		||||
fuzz_test(toxsave          .)  # Fuzzes the bootstrap process
 | 
			
		||||
 | 
			
		||||
fuzz_test(DHT              ../../toxcore)
 | 
			
		||||
fuzz_test(forwarding       ../../toxcore)
 | 
			
		||||
 
 | 
			
		||||
@@ -83,9 +83,12 @@ void setup_callbacks(Tox_Dispatch *dispatch)
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) {
 | 
			
		||||
            Tox_Err_Friend_Add err;
 | 
			
		||||
            tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &err);
 | 
			
		||||
            assert(err == TOX_ERR_FRIEND_ADD_OK || err == TOX_ERR_FRIEND_ADD_OWN_KEY
 | 
			
		||||
                || err == TOX_ERR_FRIEND_ADD_ALREADY_SENT
 | 
			
		||||
                || err == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM);
 | 
			
		||||
            if (!(err == TOX_ERR_FRIEND_ADD_OK || err == TOX_ERR_FRIEND_ADD_OWN_KEY
 | 
			
		||||
                    || err == TOX_ERR_FRIEND_ADD_ALREADY_SENT
 | 
			
		||||
                    || err == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM
 | 
			
		||||
                    || err == TOX_ERR_FRIEND_ADD_MALLOC)) {
 | 
			
		||||
                printf("unexpected error: %s\n", tox_err_friend_add_to_string(err));
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_status(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) {
 | 
			
		||||
@@ -120,7 +123,7 @@ void TestBootstrap(Fuzz_Data &input)
 | 
			
		||||
        [](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
 | 
			
		||||
            const char *message, void *user_data) {
 | 
			
		||||
            // Log to stdout.
 | 
			
		||||
            if (DEBUG) {
 | 
			
		||||
            if (Fuzz_Data::DEBUG) {
 | 
			
		||||
                std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
 | 
			
		||||
                    func, message);
 | 
			
		||||
            }
 | 
			
		||||
@@ -167,7 +170,7 @@ void TestBootstrap(Fuzz_Data &input)
 | 
			
		||||
    assert(dispatch != nullptr);
 | 
			
		||||
    setup_callbacks(dispatch);
 | 
			
		||||
 | 
			
		||||
    while (input.size > 0) {
 | 
			
		||||
    while (!input.empty()) {
 | 
			
		||||
        Tox_Err_Events_Iterate error_iterate;
 | 
			
		||||
        Tox_Events *events = tox_events_iterate(tox, true, &error_iterate);
 | 
			
		||||
        assert(tox_events_equal(null_sys.sys.get(), events, events));
 | 
			
		||||
@@ -110,9 +110,6 @@ void setup_callbacks(Tox_Dispatch *dispatch)
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) {
 | 
			
		||||
            Tox_Err_Friend_Add err;
 | 
			
		||||
            tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &err);
 | 
			
		||||
            assert(err == TOX_ERR_FRIEND_ADD_OK || err == TOX_ERR_FRIEND_ADD_OWN_KEY
 | 
			
		||||
                || err == TOX_ERR_FRIEND_ADD_ALREADY_SENT
 | 
			
		||||
                || err == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_status(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) {
 | 
			
		||||
@@ -147,7 +144,7 @@ void TestEndToEnd(Fuzz_Data &input)
 | 
			
		||||
        [](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
 | 
			
		||||
            const char *message, void *user_data) {
 | 
			
		||||
            // Log to stdout.
 | 
			
		||||
            if (DEBUG) {
 | 
			
		||||
            if (Fuzz_Data::DEBUG) {
 | 
			
		||||
                std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
 | 
			
		||||
                    func, message);
 | 
			
		||||
            }
 | 
			
		||||
@@ -170,7 +167,7 @@ void TestEndToEnd(Fuzz_Data &input)
 | 
			
		||||
    assert(dispatch != nullptr);
 | 
			
		||||
    setup_callbacks(dispatch);
 | 
			
		||||
 | 
			
		||||
    while (input.size > 0) {
 | 
			
		||||
    while (!input.empty()) {
 | 
			
		||||
        Tox_Err_Events_Iterate error_iterate;
 | 
			
		||||
        Tox_Events *events = tox_events_iterate(tox, true, &error_iterate);
 | 
			
		||||
        assert(tox_events_equal(null_sys.sys.get(), events, events));
 | 
			
		||||
 
 | 
			
		||||
@@ -20,10 +20,6 @@
 | 
			
		||||
#include "../../toxcore/tox_private.h"
 | 
			
		||||
#include "func_conversion.h"
 | 
			
		||||
 | 
			
		||||
const bool DEBUG = false;
 | 
			
		||||
 | 
			
		||||
static constexpr tox_mono_time_cb *get_self_clock =  { return self->clock; };
 | 
			
		||||
 | 
			
		||||
// TODO(iphydf): Put this somewhere shared.
 | 
			
		||||
struct Network_Addr {
 | 
			
		||||
    struct sockaddr_storage addr;
 | 
			
		||||
@@ -44,58 +40,67 @@ System::~System() { }
 | 
			
		||||
 | 
			
		||||
static int recv_common(Fuzz_Data &input, uint8_t *buf, size_t buf_len)
 | 
			
		||||
{
 | 
			
		||||
    if (input.size < 2) {
 | 
			
		||||
    if (input.size() < 2) {
 | 
			
		||||
        errno = ENOMEM;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const size_t fuzz_len = (input.data[0] << 8) | input.data[1];
 | 
			
		||||
    input.data += 2;
 | 
			
		||||
    input.size -= 2;
 | 
			
		||||
    CONSUME_OR_ABORT(const uint8_t *fuzz_len_bytes, input, 2);
 | 
			
		||||
    const std::size_t fuzz_len = (fuzz_len_bytes[0] << 8) | fuzz_len_bytes[1];
 | 
			
		||||
 | 
			
		||||
    if (fuzz_len == 0xffff) {
 | 
			
		||||
        errno = EWOULDBLOCK;
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
        if (Fuzz_Data::DEBUG) {
 | 
			
		||||
            std::printf("recvfrom: no data for tox1\n");
 | 
			
		||||
        }
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (DEBUG) {
 | 
			
		||||
    if (Fuzz_Data::DEBUG) {
 | 
			
		||||
        std::printf(
 | 
			
		||||
            "recvfrom: %zu (%02x, %02x) for tox1\n", fuzz_len, input.data[-2], input.data[-1]);
 | 
			
		||||
            "recvfrom: %zu (%02x, %02x) for tox1\n", fuzz_len, input.data()[-2], input.data()[-1]);
 | 
			
		||||
    }
 | 
			
		||||
    const size_t res = std::min(buf_len, std::min(fuzz_len, input.size));
 | 
			
		||||
    const size_t res = std::min(buf_len, std::min(fuzz_len, input.size()));
 | 
			
		||||
 | 
			
		||||
    std::copy(input.data, input.data + res, buf);
 | 
			
		||||
    input.data += res;
 | 
			
		||||
    input.size -= res;
 | 
			
		||||
    CONSUME_OR_ABORT(const uint8_t *data, input, res);
 | 
			
		||||
    std::copy(data, data + res, buf);
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename F>
 | 
			
		||||
static void *alloc_common(Fuzz_Data &data, F func)
 | 
			
		||||
static void *report_alloc(const char *name, const char *func, std::size_t size, void *ptr)
 | 
			
		||||
{
 | 
			
		||||
    CONSUME1_OR_RETURN_VAL(const uint8_t, want_alloc, data, func());
 | 
			
		||||
    if (Fuzz_Data::DEBUG) {
 | 
			
		||||
        printf("%s: %s(%zu): %s\n", name, func, size, ptr == nullptr ? "false" : "true");
 | 
			
		||||
    }
 | 
			
		||||
    return ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename F, F Func, typename... Args>
 | 
			
		||||
static void *alloc_common(const char *func, std::size_t size, Fuzz_Data &data, Args... args)
 | 
			
		||||
{
 | 
			
		||||
    CONSUME1_OR_RETURN_VAL(
 | 
			
		||||
        const bool, want_alloc, data, report_alloc("tox1", func, size, Func(args...)));
 | 
			
		||||
    if (!want_alloc) {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
    return func();
 | 
			
		||||
    return report_alloc("tox1", func, size, Func(args...));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static constexpr Memory_Funcs fuzz_memory_funcs = {
 | 
			
		||||
    /* .malloc = */
 | 
			
		||||
     {
 | 
			
		||||
        return alloc_common(self->data, [=]() { return std::malloc(size); });
 | 
			
		||||
        return alloc_common<decltype(std::malloc), std::malloc>("malloc", size, self->data, size);
 | 
			
		||||
    },
 | 
			
		||||
    /* .calloc = */
 | 
			
		||||
     {
 | 
			
		||||
        return alloc_common(self->data, [=]() { return std::calloc(nmemb, size); });
 | 
			
		||||
        return alloc_common<decltype(std::calloc), std::calloc>(
 | 
			
		||||
            "calloc", nmemb * size, self->data, nmemb, size);
 | 
			
		||||
    },
 | 
			
		||||
    /* .realloc = */
 | 
			
		||||
     {
 | 
			
		||||
        return alloc_common(self->data, [=]() { return std::realloc(ptr, size); });
 | 
			
		||||
        return alloc_common<decltype(std::realloc), std::realloc>(
 | 
			
		||||
            "realloc", size, self->data, ptr, size);
 | 
			
		||||
    },
 | 
			
		||||
    /* .free = */
 | 
			
		||||
     { std::free(ptr); },
 | 
			
		||||
@@ -110,7 +115,7 @@ static constexpr Network_Funcs fuzz_network_funcs = {
 | 
			
		||||
     {
 | 
			
		||||
        assert(sock == 42 || sock == 1337);
 | 
			
		||||
        const size_t count = random_u16(self->rng.get());
 | 
			
		||||
        return static_cast<int>(std::min(count, self->data.size));
 | 
			
		||||
        return static_cast<int>(std::min(count, self->data.size()));
 | 
			
		||||
    },
 | 
			
		||||
    /* .recv = */
 | 
			
		||||
     {
 | 
			
		||||
@@ -163,14 +168,17 @@ static constexpr Random_Funcs fuzz_random_funcs = {
 | 
			
		||||
    /* .random_bytes = */
 | 
			
		||||
     {
 | 
			
		||||
        // Amount of data is limited
 | 
			
		||||
        const size_t bytes_read = std::min(length, self->data.size);
 | 
			
		||||
        const size_t bytes_read = std::min(length, self->data.size());
 | 
			
		||||
        // Initialize everything to make MSAN and others happy
 | 
			
		||||
        std::memset(bytes, 0, length);
 | 
			
		||||
        std::copy(self->data.data, self->data.data + bytes_read, bytes);
 | 
			
		||||
        self->data.data += bytes_read;
 | 
			
		||||
        self->data.size -= bytes_read;
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
            std::printf("rng: %02x..%02x[%zu] -> tox1\n", bytes[0], bytes[length - 1], length);
 | 
			
		||||
        CONSUME_OR_ABORT(const uint8_t *data, self->data, bytes_read);
 | 
			
		||||
        std::copy(data, data + bytes_read, bytes);
 | 
			
		||||
        if (Fuzz_Data::DEBUG) {
 | 
			
		||||
            if (length == 1) {
 | 
			
		||||
                std::printf("rng: %d (0x%02x)\n", bytes[0], bytes[0]);
 | 
			
		||||
            } else {
 | 
			
		||||
                std::printf("rng: %02x..%02x[%zu]\n", bytes[0], bytes[length - 1], length);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    /* .random_uniform = */
 | 
			
		||||
@@ -194,7 +202,7 @@ Fuzz_System::Fuzz_System(Fuzz_Data &input)
 | 
			
		||||
    }
 | 
			
		||||
    , data(input)
 | 
			
		||||
{
 | 
			
		||||
    sys->mono_time_callback = get_self_clock;
 | 
			
		||||
    sys->mono_time_callback = [](void *self) { return static_cast<Fuzz_System *>(self)->clock; };
 | 
			
		||||
    sys->mono_time_user_data = this;
 | 
			
		||||
    sys->mem = mem.get();
 | 
			
		||||
    sys->ns = ns.get();
 | 
			
		||||
@@ -281,7 +289,7 @@ Null_System::Null_System()
 | 
			
		||||
        std::make_unique<Random>(Random{&null_random_funcs, this}),
 | 
			
		||||
    }
 | 
			
		||||
{
 | 
			
		||||
    sys->mono_time_callback = get_self_clock;
 | 
			
		||||
    sys->mono_time_callback = [](void *self) { return static_cast<Null_System *>(self)->clock; };
 | 
			
		||||
    sys->mono_time_user_data = this;
 | 
			
		||||
    sys->mem = mem.get();
 | 
			
		||||
    sys->ns = ns.get();
 | 
			
		||||
@@ -298,7 +306,25 @@ static uint16_t get_port(const Network_Addr *addr)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static constexpr Memory_Funcs record_memory_funcs = null_memory_funcs;
 | 
			
		||||
static constexpr Memory_Funcs record_memory_funcs = {
 | 
			
		||||
    /* .malloc = */
 | 
			
		||||
     {
 | 
			
		||||
        self->push(true);
 | 
			
		||||
        return report_alloc(self->name_, "malloc", size, std::malloc(size));
 | 
			
		||||
    },
 | 
			
		||||
    /* .calloc = */
 | 
			
		||||
     {
 | 
			
		||||
        self->push(true);
 | 
			
		||||
        return report_alloc(self->name_, "calloc", nmemb * size, std::calloc(nmemb, size));
 | 
			
		||||
    },
 | 
			
		||||
    /* .realloc = */
 | 
			
		||||
     {
 | 
			
		||||
        self->push(true);
 | 
			
		||||
        return report_alloc(self->name_, "realloc", size, std::realloc(ptr, size));
 | 
			
		||||
    },
 | 
			
		||||
    /* .free = */
 | 
			
		||||
     { std::free(ptr); },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static constexpr Network_Funcs record_network_funcs = {
 | 
			
		||||
    /* .close = */  { return 0; },
 | 
			
		||||
@@ -326,11 +352,10 @@ static constexpr Network_Funcs record_network_funcs = {
 | 
			
		||||
     {
 | 
			
		||||
        assert(sock == 42);
 | 
			
		||||
        if (self->recvq.empty()) {
 | 
			
		||||
            self->recording.push_back(0xff);
 | 
			
		||||
            self->recording.push_back(0xff);
 | 
			
		||||
            self->push("\xff\xff");
 | 
			
		||||
            errno = EWOULDBLOCK;
 | 
			
		||||
            if (DEBUG) {
 | 
			
		||||
                std::printf("recvfrom: no data for %s\n", self->name_);
 | 
			
		||||
            if (Fuzz_Data::DEBUG) {
 | 
			
		||||
                std::printf("%s: recvfrom: no data\n", self->name_);
 | 
			
		||||
            }
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
@@ -350,13 +375,13 @@ static constexpr Network_Funcs record_network_funcs = {
 | 
			
		||||
        addr->size = sizeof(struct sockaddr);
 | 
			
		||||
 | 
			
		||||
        assert(recvlen > 0 && recvlen <= INT_MAX);
 | 
			
		||||
        self->recording.push_back(recvlen >> 8);
 | 
			
		||||
        self->recording.push_back(recvlen & 0xff);
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
            std::printf("recvfrom: %zu (%02x, %02x) for %s\n", recvlen, self->recording.end()[-2],
 | 
			
		||||
                self->recording.end()[-1], self->name_);
 | 
			
		||||
        self->push(uint8_t(recvlen >> 8));
 | 
			
		||||
        self->push(uint8_t(recvlen & 0xff));
 | 
			
		||||
        if (Fuzz_Data::DEBUG) {
 | 
			
		||||
            std::printf("%s: recvfrom: %zu (%02x, %02x)\n", self->name_, recvlen,
 | 
			
		||||
                self->recording().end()[-2], self->recording().end()[-1]);
 | 
			
		||||
        }
 | 
			
		||||
        self->recording.insert(self->recording.end(), buf, buf + recvlen);
 | 
			
		||||
        self->push(buf, recvlen);
 | 
			
		||||
        return static_cast<int>(recvlen);
 | 
			
		||||
    },
 | 
			
		||||
    /* .send = */
 | 
			
		||||
@@ -390,11 +415,11 @@ static constexpr Random_Funcs record_random_funcs = {
 | 
			
		||||
     {
 | 
			
		||||
        for (size_t i = 0; i < length; ++i) {
 | 
			
		||||
            bytes[i] = simple_rng(self->seed_) & 0xff;
 | 
			
		||||
            self->recording.push_back(bytes[i]);
 | 
			
		||||
            self->push(bytes[i]);
 | 
			
		||||
        }
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
        if (Fuzz_Data::DEBUG) {
 | 
			
		||||
            std::printf(
 | 
			
		||||
                "rng: %02x..%02x[%zu] -> %s\n", bytes[0], bytes[length - 1], length, self->name_);
 | 
			
		||||
                "%s: rng: %02x..%02x[%zu]\n", self->name_, bytes[0], bytes[length - 1], length);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    /* .random_uniform = */
 | 
			
		||||
@@ -412,7 +437,7 @@ Record_System::Record_System(Global &global, uint64_t seed, const char *name)
 | 
			
		||||
    , seed_(seed)
 | 
			
		||||
    , name_(name)
 | 
			
		||||
{
 | 
			
		||||
    sys->mono_time_callback = get_self_clock;
 | 
			
		||||
    sys->mono_time_callback = [](void *self) { return static_cast<Record_System *>(self)->clock; };
 | 
			
		||||
    sys->mono_time_user_data = this;
 | 
			
		||||
    sys->mem = mem.get();
 | 
			
		||||
    sys->ns = ns.get();
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
#define C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <deque>
 | 
			
		||||
@@ -17,12 +18,19 @@
 | 
			
		||||
#include "../../toxcore/tox.h"
 | 
			
		||||
 | 
			
		||||
struct Fuzz_Data {
 | 
			
		||||
    const uint8_t *data;
 | 
			
		||||
    std::size_t size;
 | 
			
		||||
    static constexpr bool DEBUG = false;
 | 
			
		||||
    static constexpr std::size_t TRACE_TRAP = -1; // 579;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    const uint8_t *data_;
 | 
			
		||||
    const uint8_t *base_;
 | 
			
		||||
    std::size_t size_;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    Fuzz_Data(const uint8_t *input_data, std::size_t input_size)
 | 
			
		||||
        : data(input_data)
 | 
			
		||||
        , size(input_size)
 | 
			
		||||
        : data_(input_data)
 | 
			
		||||
        , base_(input_data)
 | 
			
		||||
        , size_(input_size)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -30,25 +38,54 @@ struct Fuzz_Data {
 | 
			
		||||
    Fuzz_Data(const Fuzz_Data &rhs) = delete;
 | 
			
		||||
 | 
			
		||||
    struct Consumer {
 | 
			
		||||
        const char *func;
 | 
			
		||||
        Fuzz_Data &fd;
 | 
			
		||||
 | 
			
		||||
        operator bool()
 | 
			
		||||
        {
 | 
			
		||||
            // Special case because memcpy causes UB for bool (which can't be
 | 
			
		||||
            // anything other than 0 or 1).
 | 
			
		||||
            const bool val = fd.data_[0];
 | 
			
		||||
            if (DEBUG) {
 | 
			
		||||
                std::printf("consume@%zu(%s): bool %s\n", fd.pos(), func, val ? "true" : "false");
 | 
			
		||||
            }
 | 
			
		||||
            ++fd.data_;
 | 
			
		||||
            --fd.size_;
 | 
			
		||||
            return val;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        template <typename T>
 | 
			
		||||
        operator T()
 | 
			
		||||
        {
 | 
			
		||||
            const uint8_t *bytes = fd.consume(sizeof(T));
 | 
			
		||||
            const uint8_t *bytes = fd.consume(func, sizeof(T));
 | 
			
		||||
            T val;
 | 
			
		||||
            std::memcpy(&val, bytes, sizeof(T));
 | 
			
		||||
            return val;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Consumer consume1() { return Consumer{*this}; }
 | 
			
		||||
    Consumer consume1(const char *func) { return Consumer{func, *this}; }
 | 
			
		||||
    std::size_t size() const { return size_; }
 | 
			
		||||
    std::size_t pos() const { return data_ - base_; }
 | 
			
		||||
    const uint8_t *data() const { return data_; }
 | 
			
		||||
    bool empty() const { return size_ == 0; }
 | 
			
		||||
 | 
			
		||||
    const uint8_t *consume(std::size_t count)
 | 
			
		||||
    const uint8_t *consume(const char *func, std::size_t count)
 | 
			
		||||
    {
 | 
			
		||||
        const uint8_t *val = data;
 | 
			
		||||
        data += count;
 | 
			
		||||
        size -= count;
 | 
			
		||||
        const uint8_t *val = data_;
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
            if (pos() == TRACE_TRAP) {
 | 
			
		||||
                __asm__("int $3");
 | 
			
		||||
            }
 | 
			
		||||
            if (count == 1) {
 | 
			
		||||
                std::printf("consume@%zu(%s): %d (0x%02x)\n", pos(), func, val[0], val[0]);
 | 
			
		||||
            } else if (count != 0) {
 | 
			
		||||
                std::printf("consume@%zu(%s): %02x..%02x[%zu]\n", pos(), func, val[0],
 | 
			
		||||
                    val[count - 1], count);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        data_ += count;
 | 
			
		||||
        size_ -= count;
 | 
			
		||||
        return val;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@@ -64,10 +101,10 @@ struct Fuzz_Data {
 | 
			
		||||
 * @endcode
 | 
			
		||||
 */
 | 
			
		||||
#define CONSUME1_OR_RETURN(TYPE, NAME, INPUT) \
 | 
			
		||||
    if (INPUT.size < sizeof(TYPE)) {          \
 | 
			
		||||
    if (INPUT.size() < sizeof(TYPE)) {        \
 | 
			
		||||
        return;                               \
 | 
			
		||||
    }                                         \
 | 
			
		||||
    TYPE NAME = INPUT.consume1()
 | 
			
		||||
    TYPE NAME = INPUT.consume1(__func__)
 | 
			
		||||
 | 
			
		||||
/** @brief Consumes 1 byte of the fuzzer input or returns a value if no data
 | 
			
		||||
 * available.
 | 
			
		||||
@@ -81,10 +118,10 @@ struct Fuzz_Data {
 | 
			
		||||
 * @endcode
 | 
			
		||||
 */
 | 
			
		||||
#define CONSUME1_OR_RETURN_VAL(TYPE, NAME, INPUT, VAL) \
 | 
			
		||||
    if (INPUT.size < sizeof(TYPE)) {                   \
 | 
			
		||||
    if (INPUT.size() < sizeof(TYPE)) {                 \
 | 
			
		||||
        return VAL;                                    \
 | 
			
		||||
    }                                                  \
 | 
			
		||||
    TYPE NAME = INPUT.consume1()
 | 
			
		||||
    TYPE NAME = INPUT.consume1(__func__)
 | 
			
		||||
 | 
			
		||||
/** @brief Consumes SIZE bytes of the fuzzer input or returns if not enough data available.
 | 
			
		||||
 *
 | 
			
		||||
@@ -98,39 +135,55 @@ struct Fuzz_Data {
 | 
			
		||||
 * @endcode
 | 
			
		||||
 */
 | 
			
		||||
#define CONSUME_OR_RETURN(DECL, INPUT, SIZE) \
 | 
			
		||||
    if (INPUT.size < SIZE) {                 \
 | 
			
		||||
    if (INPUT.size() < SIZE) {               \
 | 
			
		||||
        return;                              \
 | 
			
		||||
    }                                        \
 | 
			
		||||
    DECL = INPUT.consume(SIZE)
 | 
			
		||||
    DECL = INPUT.consume(__func__, SIZE)
 | 
			
		||||
 | 
			
		||||
#define CONSUME_OR_RETURN_VAL(DECL, INPUT, SIZE, VAL) \
 | 
			
		||||
    if (INPUT.size < SIZE) {                          \
 | 
			
		||||
    if (INPUT.size() < SIZE) {                        \
 | 
			
		||||
        return VAL;                                   \
 | 
			
		||||
    }                                                 \
 | 
			
		||||
    DECL = INPUT.consume(SIZE)
 | 
			
		||||
    DECL = INPUT.consume(__func__, SIZE)
 | 
			
		||||
 | 
			
		||||
inline void fuzz_select_target(uint8_t selector, Fuzz_Data &input)
 | 
			
		||||
{
 | 
			
		||||
    // The selector selected no function, so we do nothing and rely on the
 | 
			
		||||
    // fuzzer to come up with a better selector.
 | 
			
		||||
}
 | 
			
		||||
#define CONSUME_OR_ABORT(DECL, INPUT, SIZE) \
 | 
			
		||||
    if (INPUT.size() < SIZE) {              \
 | 
			
		||||
        abort();                            \
 | 
			
		||||
    }                                       \
 | 
			
		||||
    DECL = INPUT.consume(__func__, SIZE)
 | 
			
		||||
 | 
			
		||||
template <typename Arg, typename... Args>
 | 
			
		||||
void fuzz_select_target(uint8_t selector, Fuzz_Data &input, Arg &&fn, Args &&...args)
 | 
			
		||||
{
 | 
			
		||||
    if (selector == sizeof...(Args)) {
 | 
			
		||||
        return fn(input);
 | 
			
		||||
using Fuzz_Target = void (*)(Fuzz_Data &input);
 | 
			
		||||
 | 
			
		||||
template <Fuzz_Target... Args>
 | 
			
		||||
struct Fuzz_Target_Selector;
 | 
			
		||||
 | 
			
		||||
template <Fuzz_Target Arg, Fuzz_Target... Args>
 | 
			
		||||
struct Fuzz_Target_Selector<Arg, Args...> {
 | 
			
		||||
    static void select(uint8_t selector, Fuzz_Data &input)
 | 
			
		||||
    {
 | 
			
		||||
        if (selector == sizeof...(Args)) {
 | 
			
		||||
            return Arg(input);
 | 
			
		||||
        }
 | 
			
		||||
        return Fuzz_Target_Selector<Args...>::select(selector, input);
 | 
			
		||||
    }
 | 
			
		||||
    return fuzz_select_target(selector - 1, input, std::forward<Args>(args)...);
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename... Args>
 | 
			
		||||
void fuzz_select_target(const uint8_t *data, std::size_t size, Args &&...args)
 | 
			
		||||
template <>
 | 
			
		||||
struct Fuzz_Target_Selector<> {
 | 
			
		||||
    static void select(uint8_t selector, Fuzz_Data &input)
 | 
			
		||||
    {
 | 
			
		||||
        // The selector selected no function, so we do nothing and rely on the
 | 
			
		||||
        // fuzzer to come up with a better selector.
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <Fuzz_Target... Args>
 | 
			
		||||
void fuzz_select_target(const uint8_t *data, std::size_t size)
 | 
			
		||||
{
 | 
			
		||||
    Fuzz_Data input{data, size};
 | 
			
		||||
 | 
			
		||||
    CONSUME1_OR_RETURN(const uint8_t, selector, input);
 | 
			
		||||
    return fuzz_select_target(selector, input, std::forward<Args>(args)...);
 | 
			
		||||
    return Fuzz_Target_Selector<Args...>::select(selector, input);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Memory;
 | 
			
		||||
@@ -138,6 +191,18 @@ struct Network;
 | 
			
		||||
struct Random;
 | 
			
		||||
 | 
			
		||||
struct System {
 | 
			
		||||
    /** @brief Deterministic system clock for this instance.
 | 
			
		||||
     *
 | 
			
		||||
     * Different instances can evolve independently. The time is initialised
 | 
			
		||||
     * with a large number, because otherwise many zero-initialised "empty"
 | 
			
		||||
     * friends inside toxcore will be "not timed out" for a long time, messing
 | 
			
		||||
     * up some logic. Tox moderately depends on the clock being fairly high up
 | 
			
		||||
     * (not close to 0).
 | 
			
		||||
     *
 | 
			
		||||
     * We make it a nice large round number so we can recognise it when debugging.
 | 
			
		||||
     */
 | 
			
		||||
    uint64_t clock = 1000000000;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Tox_System> sys;
 | 
			
		||||
    std::unique_ptr<Memory> mem;
 | 
			
		||||
    std::unique_ptr<Network> ns;
 | 
			
		||||
@@ -150,16 +215,6 @@ struct System {
 | 
			
		||||
    // Not inline because sizeof of the above 2 structs is not known everywhere.
 | 
			
		||||
    ~System();
 | 
			
		||||
 | 
			
		||||
    /** @brief Deterministic system clock for this instance.
 | 
			
		||||
     *
 | 
			
		||||
     * Different instances can evolve independently. The time is initialised
 | 
			
		||||
     * with a large number, because otherwise many zero-initialised "empty"
 | 
			
		||||
     * friends inside toxcore will be "not timed out" for a long time, messing
 | 
			
		||||
     * up some logic. Tox moderately depends on the clock being fairly high up
 | 
			
		||||
     * (not close to 0).
 | 
			
		||||
     */
 | 
			
		||||
    uint64_t clock = UINT32_MAX;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * During bootstrap, move the time forward a decent amount, because friend
 | 
			
		||||
     * finding and bootstrapping takes significant (around 10 seconds) wall
 | 
			
		||||
@@ -210,6 +265,8 @@ struct Null_System : System {
 | 
			
		||||
 * initialised with the same seed will be identical (same keys, etc.).
 | 
			
		||||
 */
 | 
			
		||||
struct Record_System : System {
 | 
			
		||||
    static constexpr bool DEBUG = Fuzz_Data::DEBUG;
 | 
			
		||||
 | 
			
		||||
    /** @brief State shared between all tox instances. */
 | 
			
		||||
    struct Global {
 | 
			
		||||
        /** @brief Bound UDP ports and their system instance.
 | 
			
		||||
@@ -231,13 +288,60 @@ struct Record_System : System {
 | 
			
		||||
 | 
			
		||||
    std::deque<std::pair<uint16_t, std::vector<uint8_t>>> recvq;
 | 
			
		||||
    uint16_t port = 0;  //!< Sending port for this system instance.
 | 
			
		||||
    std::vector<uint8_t> recording;
 | 
			
		||||
 | 
			
		||||
    explicit Record_System(Global &global, uint64_t seed, const char *name);
 | 
			
		||||
    Record_System(Global &global, uint64_t seed, const char *name);
 | 
			
		||||
    Record_System(const Record_System &) = delete;
 | 
			
		||||
    Record_System operator=(const Record_System &) = delete;
 | 
			
		||||
 | 
			
		||||
    /** @brief Deposit a network packet in this instance's recvq.
 | 
			
		||||
     */
 | 
			
		||||
    void receive(uint16_t send_port, const uint8_t *buf, size_t len);
 | 
			
		||||
 | 
			
		||||
    void push(bool byte)
 | 
			
		||||
    {
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
            if (recording_.size() == Fuzz_Data::TRACE_TRAP) {
 | 
			
		||||
                __asm__("int $3");
 | 
			
		||||
            }
 | 
			
		||||
            std::printf("%s: produce@%zu(bool %s)\n", name_, recording_.size(), byte ? "true" : "false");
 | 
			
		||||
        }
 | 
			
		||||
        recording_.push_back(byte);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void push(uint8_t byte)
 | 
			
		||||
    {
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
            if (recording_.size() == Fuzz_Data::TRACE_TRAP) {
 | 
			
		||||
                __asm__("int $3");
 | 
			
		||||
            }
 | 
			
		||||
            std::printf("%s: produce@%zu(%u (0x%02x))\n", name_, recording_.size(), byte, byte);
 | 
			
		||||
        }
 | 
			
		||||
        recording_.push_back(byte);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void push(const uint8_t *bytes, std::size_t size)
 | 
			
		||||
    {
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
            if (recording_.size() == Fuzz_Data::TRACE_TRAP) {
 | 
			
		||||
                __asm__("int $3");
 | 
			
		||||
            }
 | 
			
		||||
            std::printf("%s: produce@%zu(%02x..%02x[%zu])\n", name_, recording_.size(), bytes[0],
 | 
			
		||||
                bytes[size - 1], size);
 | 
			
		||||
        }
 | 
			
		||||
        recording_.insert(recording_.end(), bytes, bytes + size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <std::size_t N>
 | 
			
		||||
    void push(const char (&bytes)[N])
 | 
			
		||||
    {
 | 
			
		||||
        push(reinterpret_cast<const uint8_t *>(bytes), N - 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const std::vector<uint8_t> &recording() const { return recording_; }
 | 
			
		||||
    std::vector<uint8_t> take_recording() const { return std::move(recording_); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::vector<uint8_t> recording_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** @brief Enable debug logging.
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@
 | 
			
		||||
 *
 | 
			
		||||
 * Usage:
 | 
			
		||||
 *
 | 
			
		||||
 *   bazel build //c-toxcore/testing/fuzzing:protodump_bin && \
 | 
			
		||||
 *     bazel-bin/c-toxcore/testing/fuzzing/protodump_bin
 | 
			
		||||
 *   bazel build //c-toxcore/testing/fuzzing:protodump && \
 | 
			
		||||
 *     bazel-bin/c-toxcore/testing/fuzzing/protodump
 | 
			
		||||
 */
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
@@ -165,15 +165,14 @@ void setup_callbacks(Tox_Dispatch *dispatch)
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dump(std::vector<uint8_t> &recording, const char *filename)
 | 
			
		||||
void dump(std::vector<uint8_t> recording, const char *filename)
 | 
			
		||||
{
 | 
			
		||||
    std::printf("%zu bytes: %s\n", recording.size(), filename);
 | 
			
		||||
    std::ofstream(filename, std::ios::binary)
 | 
			
		||||
        .write(reinterpret_cast<const char *>(recording.data()), recording.size());
 | 
			
		||||
    recording.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecordBootstrap()
 | 
			
		||||
void RecordBootstrap(const char *init, const char *bootstrap)
 | 
			
		||||
{
 | 
			
		||||
    Record_System::Global global;
 | 
			
		||||
 | 
			
		||||
@@ -258,13 +257,17 @@ void RecordBootstrap()
 | 
			
		||||
        sys1.clock += clock_increment;
 | 
			
		||||
        sys2.clock += clock_increment;
 | 
			
		||||
 | 
			
		||||
        sys1.recording.push_back(clock_increment);
 | 
			
		||||
        sys2.recording.push_back(clock_increment);
 | 
			
		||||
        if (Fuzz_Data::DEBUG) {
 | 
			
		||||
            printf("tox1: rng: %d (for clock)\n", clock_increment);
 | 
			
		||||
            printf("tox2: rng: %d (for clock)\n", clock_increment);
 | 
			
		||||
        }
 | 
			
		||||
        sys1.push(clock_increment);
 | 
			
		||||
        sys2.push(clock_increment);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE
 | 
			
		||||
        || tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE) {
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
        if (Fuzz_Data::DEBUG) {
 | 
			
		||||
            std::printf("tox1: %d, tox2: %d\n", tox_self_get_connection_status(tox1),
 | 
			
		||||
                tox_self_get_connection_status(tox2));
 | 
			
		||||
        }
 | 
			
		||||
@@ -279,7 +282,7 @@ void RecordBootstrap()
 | 
			
		||||
 | 
			
		||||
    while (tox_friend_get_connection_status(tox2, friend_number, nullptr) == TOX_CONNECTION_NONE
 | 
			
		||||
        || tox_friend_get_connection_status(tox1, 0, nullptr) == TOX_CONNECTION_NONE) {
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
        if (Fuzz_Data::DEBUG) {
 | 
			
		||||
            std::printf("tox1: %d, tox2: %d, tox1 -> tox2: %d, tox2 -> tox1: %d\n",
 | 
			
		||||
                tox_self_get_connection_status(tox1), tox_self_get_connection_status(tox2),
 | 
			
		||||
                tox_friend_get_connection_status(tox1, 0, nullptr),
 | 
			
		||||
@@ -290,10 +293,10 @@ void RecordBootstrap()
 | 
			
		||||
 | 
			
		||||
    std::printf("tox clients connected\n");
 | 
			
		||||
 | 
			
		||||
    dump(sys1.recording, "tools/toktok-fuzzer/init/e2e_fuzz_test.dat");
 | 
			
		||||
    dump(sys1.take_recording(), init);
 | 
			
		||||
 | 
			
		||||
    while (done1 < MESSAGE_COUNT && done2 < MESSAGE_COUNT) {
 | 
			
		||||
        if (DEBUG) {
 | 
			
		||||
        if (Fuzz_Data::DEBUG) {
 | 
			
		||||
            std::printf("tox1: %d, tox2: %d, tox1 -> tox2: %d, tox2 -> tox1: %d\n",
 | 
			
		||||
                tox_self_get_connection_status(tox1), tox_self_get_connection_status(tox2),
 | 
			
		||||
                tox_friend_get_connection_status(tox1, 0, nullptr),
 | 
			
		||||
@@ -308,9 +311,18 @@ void RecordBootstrap()
 | 
			
		||||
    tox_kill(tox2);
 | 
			
		||||
    tox_kill(tox1);
 | 
			
		||||
 | 
			
		||||
    dump(sys1.recording, "tools/toktok-fuzzer/corpus/e2e_fuzz_test/bootstrap.dat");
 | 
			
		||||
    dump(sys1.recording(), bootstrap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(void) { RecordBootstrap(); }
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
    const char *init = "tools/toktok-fuzzer/init/e2e_fuzz_test.dat";
 | 
			
		||||
    const char *bootstrap = "tools/toktok-fuzzer/corpus/e2e_fuzz_test/bootstrap.dat";
 | 
			
		||||
    if (argc == 3) {
 | 
			
		||||
        init = argv[1];
 | 
			
		||||
        bootstrap = argv[2];
 | 
			
		||||
    }
 | 
			
		||||
    RecordBootstrap(init, bootstrap);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,14 +11,7 @@
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Whether to abort the program if a friend connection can be established.
 | 
			
		||||
 *
 | 
			
		||||
 * This is useful to make the fuzzer produce minimal startup data so the
 | 
			
		||||
 * interesting part of the fuzzer (the part that comes after the friend
 | 
			
		||||
 * connection is established) can run sooner and thus more frequently.
 | 
			
		||||
 */
 | 
			
		||||
constexpr bool REDUCE_PROTODUMP = false;
 | 
			
		||||
constexpr bool PROTODUMP_DEBUG = Fuzz_Data::DEBUG;
 | 
			
		||||
 | 
			
		||||
void setup_callbacks(Tox_Dispatch *dispatch)
 | 
			
		||||
{
 | 
			
		||||
@@ -32,10 +25,7 @@ void setup_callbacks(Tox_Dispatch *dispatch)
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_conference_invite(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Conference_Invite *event, void *user_data) {
 | 
			
		||||
            const uint32_t friend_number = tox_event_conference_invite_get_friend_number(event);
 | 
			
		||||
            const uint8_t *cookie = tox_event_conference_invite_get_cookie(event);
 | 
			
		||||
            const uint32_t cookie_length = tox_event_conference_invite_get_cookie_length(event);
 | 
			
		||||
            tox_conference_join(tox, friend_number, cookie, cookie_length, nullptr);
 | 
			
		||||
            assert(event == nullptr);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_conference_message(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Conference_Message *event, void *user_data) {
 | 
			
		||||
@@ -59,9 +49,7 @@ void setup_callbacks(Tox_Dispatch *dispatch)
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_file_recv(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_File_Recv *event, void *user_data) {
 | 
			
		||||
            const uint32_t friend_number = tox_event_file_recv_get_friend_number(event);
 | 
			
		||||
            const uint32_t file_number = tox_event_file_recv_get_file_number(event);
 | 
			
		||||
            tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, nullptr);
 | 
			
		||||
            assert(event == nullptr);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_file_recv_chunk(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_File_Recv_Chunk *event, void *user_data) {
 | 
			
		||||
@@ -76,58 +64,65 @@ void setup_callbacks(Tox_Dispatch *dispatch)
 | 
			
		||||
            // OK: friend came online.
 | 
			
		||||
            const uint32_t friend_number
 | 
			
		||||
                = tox_event_friend_connection_status_get_friend_number(event);
 | 
			
		||||
            assert(friend_number != UINT32_MAX);
 | 
			
		||||
            assert(friend_number == 0);
 | 
			
		||||
            const uint8_t message = 'A';
 | 
			
		||||
            Tox_Err_Friend_Send_Message err;
 | 
			
		||||
            tox_friend_send_message(tox, friend_number, TOX_MESSAGE_TYPE_NORMAL, &message, 1, &err);
 | 
			
		||||
            assert(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_lossless_packet(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Lossless_Packet *event, void *user_data) {
 | 
			
		||||
            const uint32_t friend_number
 | 
			
		||||
                = tox_event_friend_lossless_packet_get_friend_number(event);
 | 
			
		||||
            const uint32_t data_length = tox_event_friend_lossless_packet_get_data_length(event);
 | 
			
		||||
            const uint8_t *data = tox_event_friend_lossless_packet_get_data(event);
 | 
			
		||||
            tox_friend_send_lossless_packet(tox, friend_number, data, data_length, nullptr);
 | 
			
		||||
            assert(event == nullptr);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_lossy_packet(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Lossy_Packet *event, void *user_data) {
 | 
			
		||||
            const uint32_t friend_number = tox_event_friend_lossy_packet_get_friend_number(event);
 | 
			
		||||
            const uint32_t data_length = tox_event_friend_lossy_packet_get_data_length(event);
 | 
			
		||||
            const uint8_t *data = tox_event_friend_lossy_packet_get_data(event);
 | 
			
		||||
            tox_friend_send_lossy_packet(tox, friend_number, data, data_length, nullptr);
 | 
			
		||||
            assert(event == nullptr);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_message(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Message *event, void *user_data) {
 | 
			
		||||
            const uint32_t friend_number = tox_event_friend_message_get_friend_number(event);
 | 
			
		||||
            const Tox_Message_Type type = tox_event_friend_message_get_type(event);
 | 
			
		||||
            assert(friend_number == 0);
 | 
			
		||||
            const uint32_t message_length = tox_event_friend_message_get_message_length(event);
 | 
			
		||||
            assert(message_length == 1);
 | 
			
		||||
            const uint8_t *message = tox_event_friend_message_get_message(event);
 | 
			
		||||
            tox_friend_send_message(tox, friend_number, type, message, message_length, nullptr);
 | 
			
		||||
            const uint8_t reply = message[0] + 1;
 | 
			
		||||
            Tox_Err_Friend_Send_Message err;
 | 
			
		||||
            tox_friend_send_message(tox, friend_number, TOX_MESSAGE_TYPE_NORMAL, &reply, 1, &err);
 | 
			
		||||
            assert(err == TOX_ERR_FRIEND_SEND_MESSAGE_OK);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_name(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Name *event, void *user_data) {
 | 
			
		||||
            // OK: friend name received.
 | 
			
		||||
            const uint32_t friend_number = tox_event_friend_name_get_friend_number(event);
 | 
			
		||||
            assert(friend_number == 0);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_read_receipt(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Read_Receipt *event, void *user_data) {
 | 
			
		||||
            // OK: message has been received.
 | 
			
		||||
            const uint32_t friend_number = tox_event_friend_read_receipt_get_friend_number(event);
 | 
			
		||||
            assert(friend_number == 0);
 | 
			
		||||
            const uint32_t message_id = tox_event_friend_read_receipt_get_message_id(event);
 | 
			
		||||
            uint32_t *done = static_cast<uint32_t *>(user_data);
 | 
			
		||||
            *done = std::max(*done, message_id);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_request(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) {
 | 
			
		||||
            Tox_Err_Friend_Add err;
 | 
			
		||||
            tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &err);
 | 
			
		||||
            assert(err == TOX_ERR_FRIEND_ADD_OK || err == TOX_ERR_FRIEND_ADD_OWN_KEY
 | 
			
		||||
                || err == TOX_ERR_FRIEND_ADD_ALREADY_SENT
 | 
			
		||||
                || err == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_status(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) {
 | 
			
		||||
            // OK: friend status received.
 | 
			
		||||
            const uint32_t friend_number = tox_event_friend_status_get_friend_number(event);
 | 
			
		||||
            assert(friend_number == 0);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_status_message(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Status_Message *event, void *user_data) {
 | 
			
		||||
            // OK: friend status message received.
 | 
			
		||||
            const uint32_t friend_number = tox_event_friend_status_message_get_friend_number(event);
 | 
			
		||||
            assert(friend_number == 0);
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_friend_typing(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Friend_Typing *event, void *user_data) {
 | 
			
		||||
            // OK: friend may be typing.
 | 
			
		||||
            const uint32_t friend_number = tox_event_friend_typing_get_friend_number(event);
 | 
			
		||||
            assert(friend_number == 0);
 | 
			
		||||
            assert(!tox_event_friend_typing_get_typing(event));
 | 
			
		||||
        });
 | 
			
		||||
    tox_events_callback_self_connection_status(
 | 
			
		||||
        dispatch, [](Tox *tox, const Tox_Event_Self_Connection_Status *event, void *user_data) {
 | 
			
		||||
@@ -137,6 +132,15 @@ void setup_callbacks(Tox_Dispatch *dispatch)
 | 
			
		||||
 | 
			
		||||
void TestEndToEnd(Fuzz_Data &input)
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether to abort the program if a friend connection can be established.
 | 
			
		||||
     *
 | 
			
		||||
     * This is useful to make the fuzzer produce minimal startup data so the
 | 
			
		||||
     * interesting part of the fuzzer (the part that comes after the friend
 | 
			
		||||
     * connection is established) can run sooner and thus more frequently.
 | 
			
		||||
     */
 | 
			
		||||
    const bool PROTODUMP_REDUCE = getenv("PROTODUMP_REDUCE") != nullptr;
 | 
			
		||||
 | 
			
		||||
    Fuzz_System sys(input);
 | 
			
		||||
 | 
			
		||||
    Ptr<Tox_Options> opts(tox_options_new(nullptr), tox_options_free);
 | 
			
		||||
@@ -148,7 +152,7 @@ void TestEndToEnd(Fuzz_Data &input)
 | 
			
		||||
        [](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
 | 
			
		||||
            const char *message, void *user_data) {
 | 
			
		||||
            // Log to stdout.
 | 
			
		||||
            if (DEBUG) {
 | 
			
		||||
            if (PROTODUMP_DEBUG) {
 | 
			
		||||
                std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
 | 
			
		||||
                    func, message);
 | 
			
		||||
            }
 | 
			
		||||
@@ -171,20 +175,26 @@ void TestEndToEnd(Fuzz_Data &input)
 | 
			
		||||
    assert(dispatch != nullptr);
 | 
			
		||||
    setup_callbacks(dispatch);
 | 
			
		||||
 | 
			
		||||
    while (input.size > 0) {
 | 
			
		||||
    while (!input.empty()) {
 | 
			
		||||
        Tox_Err_Events_Iterate error_iterate;
 | 
			
		||||
        Tox_Events *events = tox_events_iterate(tox, true, &error_iterate);
 | 
			
		||||
        assert(tox_events_equal(tox_get_system(tox), events, events));
 | 
			
		||||
        tox_events_equal(tox_get_system(tox), events, events);  // TODO(iphydf): assert?
 | 
			
		||||
        tox_dispatch_invoke(dispatch, events, tox, nullptr);
 | 
			
		||||
        tox_events_free(events);
 | 
			
		||||
        sys.clock += std::max(System::MIN_ITERATION_INTERVAL, random_u08(sys.rng.get()));
 | 
			
		||||
        const uint8_t clock_increment = random_u08(sys.rng.get());
 | 
			
		||||
        if (PROTODUMP_DEBUG) {
 | 
			
		||||
            printf("clock increment: %d\n", clock_increment);
 | 
			
		||||
        }
 | 
			
		||||
        sys.clock += std::max(System::MIN_ITERATION_INTERVAL, clock_increment);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (REDUCE_PROTODUMP) {
 | 
			
		||||
    if (PROTODUMP_REDUCE) {
 | 
			
		||||
        assert(tox_friend_get_connection_status(tox, 0, nullptr) != 2);
 | 
			
		||||
    } else {
 | 
			
		||||
        printf("friend: %d\n", tox_friend_get_connection_status(tox, 0, nullptr));
 | 
			
		||||
        printf("self: %d\n", tox_self_get_connection_status(tox));
 | 
			
		||||
        assert(tox_friend_get_connection_status(tox, 0, nullptr) == 2);
 | 
			
		||||
        assert(input.empty());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tox_dispatch_free(dispatch);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								external/toxcore/c-toxcore/testing/fuzzing/rebuild_protodump
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										14
									
								
								external/toxcore/c-toxcore/testing/fuzzing/rebuild_protodump
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
set -eux
 | 
			
		||||
 | 
			
		||||
bazel test --config=asan-libfuzzer //c-toxcore/testing/fuzzing:protodump_reduce_test
 | 
			
		||||
 | 
			
		||||
bazel build --config=asan-libfuzzer //c-toxcore/testing/fuzzing:protodump
 | 
			
		||||
bazel-bin/c-toxcore/testing/fuzzing/protodump | grep -v '^tox2'
 | 
			
		||||
 | 
			
		||||
bazel build --config=asan-libfuzzer //c-toxcore/testing/fuzzing:protodump_reduce_bin
 | 
			
		||||
bazel-bin/c-toxcore/testing/fuzzing/protodump_reduce_bin "$PWD/tools/toktok-fuzzer/init/e2e_fuzz_test.dat"
 | 
			
		||||
 | 
			
		||||
#export PROTODUMP_REDUCE=1
 | 
			
		||||
#bazel-bin/c-toxcore/testing/fuzzing/protodump_reduce_bin -minimize_crash=1 "$PWD/tools/toktok-fuzzer/init/e2e_fuzz_test.dat"
 | 
			
		||||
@@ -17,7 +17,7 @@ void TestSaveDataLoading(Fuzz_Data &input)
 | 
			
		||||
    assert(tox_options != nullptr);
 | 
			
		||||
    assert(error_options == TOX_ERR_OPTIONS_NEW_OK);
 | 
			
		||||
 | 
			
		||||
    const size_t savedata_size = input.size;
 | 
			
		||||
    const size_t savedata_size = input.size();
 | 
			
		||||
    CONSUME_OR_RETURN(const uint8_t *savedata, input, savedata_size);
 | 
			
		||||
 | 
			
		||||
    Null_System sys;
 | 
			
		||||
							
								
								
									
										52
									
								
								external/toxcore/c-toxcore/testing/run_afl.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										52
									
								
								external/toxcore/c-toxcore/testing/run_afl.sh
									
									
									
									
										vendored
									
									
								
							@@ -5,7 +5,7 @@ COMMON_CMAKE_OPTIONS="-DCMAKE_C_COMPILER=afl-clang-lto -DCMAKE_CXX_COMPILER=afl-
 | 
			
		||||
# move to repo root
 | 
			
		||||
cd ../
 | 
			
		||||
 | 
			
		||||
# build fuzzer target UBSAN
 | 
			
		||||
# build fuzz_test target UBSAN
 | 
			
		||||
mkdir -p _afl_build_ubsan
 | 
			
		||||
cd _afl_build_ubsan
 | 
			
		||||
 | 
			
		||||
@@ -14,14 +14,14 @@ export AFL_USE_UBSAN=1
 | 
			
		||||
# build c-toxcore using afl instrumentation
 | 
			
		||||
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzzer
 | 
			
		||||
# build fuzz_test target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzz_test
 | 
			
		||||
 | 
			
		||||
unset AFL_USE_UBSAN
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target MSAN
 | 
			
		||||
# build fuzz_test target MSAN
 | 
			
		||||
mkdir -p _afl_build_msan
 | 
			
		||||
cd _afl_build_msan
 | 
			
		||||
 | 
			
		||||
@@ -30,14 +30,14 @@ export AFL_USE_MSAN=1
 | 
			
		||||
# build c-toxcore using afl instrumentation
 | 
			
		||||
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzzer
 | 
			
		||||
# build fuzz_test target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzz_test
 | 
			
		||||
 | 
			
		||||
unset AFL_USE_MSAN
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target ASAN
 | 
			
		||||
# build fuzz_test target ASAN
 | 
			
		||||
mkdir -p _afl_build_asan
 | 
			
		||||
cd _afl_build_asan
 | 
			
		||||
 | 
			
		||||
@@ -46,26 +46,26 @@ export AFL_USE_ASAN=1
 | 
			
		||||
# build c-toxcore using afl instrumentation
 | 
			
		||||
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzzer
 | 
			
		||||
# build fuzz_test target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzz_test
 | 
			
		||||
 | 
			
		||||
unset AFL_USE_ASAN
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target without sanitizers for afl-tmin
 | 
			
		||||
# build fuzz_test target without sanitizers for afl-tmin
 | 
			
		||||
mkdir -p _afl_build
 | 
			
		||||
cd _afl_build
 | 
			
		||||
 | 
			
		||||
# build c-toxcore using afl instrumentation
 | 
			
		||||
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzzer
 | 
			
		||||
# build fuzz_test target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzz_test
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target with CmpLog
 | 
			
		||||
# build fuzz_test target with CmpLog
 | 
			
		||||
mkdir -p _afl_build_cmplog
 | 
			
		||||
cd _afl_build_cmplog
 | 
			
		||||
 | 
			
		||||
@@ -74,27 +74,27 @@ export AFL_LLVM_CMPLOG=1
 | 
			
		||||
# build c-toxcore using afl instrumentation
 | 
			
		||||
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzzer
 | 
			
		||||
# build fuzz_test target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzz_test
 | 
			
		||||
 | 
			
		||||
unset AFL_LLVM_CMPLOG
 | 
			
		||||
 | 
			
		||||
cd ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target for code coverage
 | 
			
		||||
# build fuzz_test target for code coverage
 | 
			
		||||
mkdir -p _cov_build
 | 
			
		||||
cd _cov_build
 | 
			
		||||
 | 
			
		||||
# build c-toxcore using afl instrumentation
 | 
			
		||||
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-fprofile-arcs -ftest-coverage" -DCMAKE_C_FLAGS="-fprofile-arcs -ftest-coverage" -DCMAKE_VERBOSE_MAKEFILE=ON "$COMMON_CMAKE_OPTIONS" ..
 | 
			
		||||
 | 
			
		||||
# build fuzzer target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzzer
 | 
			
		||||
# build fuzz_test target
 | 
			
		||||
cmake --build ./ --target bootstrap_fuzz_test
 | 
			
		||||
 | 
			
		||||
# back to repo root
 | 
			
		||||
cd ../
 | 
			
		||||
 | 
			
		||||
# Create fuzzer working directory
 | 
			
		||||
# Create fuzz_test working directory
 | 
			
		||||
 | 
			
		||||
mkdir -p _afl_out
 | 
			
		||||
 | 
			
		||||
@@ -106,21 +106,21 @@ export AFL_AUTORESUME=1
 | 
			
		||||
# faster startup
 | 
			
		||||
export AFL_FAST_CAL=1
 | 
			
		||||
 | 
			
		||||
echo "connect to the fuzzers using: screen -x fuzz"
 | 
			
		||||
echo "connect to the fuzz_tests using: screen -x fuzz"
 | 
			
		||||
echo "if fuzzing doesn't start execute the following as root:"
 | 
			
		||||
echo ""
 | 
			
		||||
echo "echo core >/proc/sys/kernel/core_pattern"
 | 
			
		||||
echo "echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor"
 | 
			
		||||
 | 
			
		||||
# Main fuzzer, keeps complete corpus
 | 
			
		||||
screen -dmS fuzz afl-fuzz -M fuzz0 "$AFL_ARGS" -c ./_afl_build_cmplog/bootstrap_fuzzer ./_afl_build/bootstrap_fuzzer
 | 
			
		||||
# Main fuzz_test, keeps complete corpus
 | 
			
		||||
screen -dmS fuzz afl-fuzz -M fuzz0 "$AFL_ARGS" -c ./_afl_build_cmplog/bootstrap_fuzz_test ./_afl_build/bootstrap_fuzz_test
 | 
			
		||||
sleep 10s
 | 
			
		||||
 | 
			
		||||
# Secondary fuzzers
 | 
			
		||||
screen -S fuzz -X screen afl-fuzz -S fuzz1 "$AFL_ARGS" -- ./_afl_build_msan/bootstrap_fuzzer
 | 
			
		||||
# Secondary fuzz_tests
 | 
			
		||||
screen -S fuzz -X screen afl-fuzz -S fuzz1 "$AFL_ARGS" -- ./_afl_build_msan/bootstrap_fuzz_test
 | 
			
		||||
sleep 1s
 | 
			
		||||
 | 
			
		||||
screen -S fuzz -X screen afl-fuzz -S fuzz2 "$AFL_ARGS" ./_afl_build_ubsan/bootstrap_fuzzer
 | 
			
		||||
screen -S fuzz -X screen afl-fuzz -S fuzz2 "$AFL_ARGS" ./_afl_build_ubsan/bootstrap_fuzz_test
 | 
			
		||||
sleep 1s
 | 
			
		||||
 | 
			
		||||
screen -S fuzz -X screen afl-fuzz -S fuzz3 "$AFL_ARGS" ./_afl_build_asan/bootstrap_fuzzer
 | 
			
		||||
screen -S fuzz -X screen afl-fuzz -S fuzz3 "$AFL_ARGS" ./_afl_build_asan/bootstrap_fuzz_test
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								external/toxcore/c-toxcore/toxcore/BUILD.bazel
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								external/toxcore/c-toxcore/toxcore/BUILD.bazel
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,5 @@
 | 
			
		||||
load("@rules_cc//cc:defs.bzl", "cc_test")
 | 
			
		||||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
 | 
			
		||||
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test")
 | 
			
		||||
load("//tools:no_undefined.bzl", "cc_library")
 | 
			
		||||
 | 
			
		||||
exports_files(
 | 
			
		||||
    srcs = [
 | 
			
		||||
@@ -12,6 +11,7 @@ exports_files(
 | 
			
		||||
 | 
			
		||||
cc_library(
 | 
			
		||||
    name = "test_util",
 | 
			
		||||
    testonly = True,
 | 
			
		||||
    srcs = ["test_util.cc"],
 | 
			
		||||
    hdrs = ["test_util.hh"],
 | 
			
		||||
)
 | 
			
		||||
@@ -52,6 +52,17 @@ cc_library(
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
cc_library(
 | 
			
		||||
    name = "mem_test_util",
 | 
			
		||||
    testonly = True,
 | 
			
		||||
    srcs = ["mem_test_util.cc"],
 | 
			
		||||
    hdrs = ["mem_test_util.hh"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":mem",
 | 
			
		||||
        ":test_util",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
cc_test(
 | 
			
		||||
    name = "mem_test",
 | 
			
		||||
    size = "small",
 | 
			
		||||
@@ -162,6 +173,7 @@ cc_library(
 | 
			
		||||
 | 
			
		||||
cc_library(
 | 
			
		||||
    name = "crypto_core_test_util",
 | 
			
		||||
    testonly = True,
 | 
			
		||||
    srcs = ["crypto_core_test_util.cc"],
 | 
			
		||||
    hdrs = ["crypto_core_test_util.hh"],
 | 
			
		||||
    deps = [
 | 
			
		||||
@@ -240,6 +252,7 @@ cc_test(
 | 
			
		||||
    size = "small",
 | 
			
		||||
    srcs = ["mono_time_test.cc"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":mem_test_util",
 | 
			
		||||
        ":mono_time",
 | 
			
		||||
        "@com_google_googletest//:gtest",
 | 
			
		||||
        "@com_google_googletest//:gtest_main",
 | 
			
		||||
@@ -292,6 +305,7 @@ cc_library(
 | 
			
		||||
 | 
			
		||||
cc_library(
 | 
			
		||||
    name = "network_test_util",
 | 
			
		||||
    testonly = True,
 | 
			
		||||
    srcs = ["network_test_util.cc"],
 | 
			
		||||
    hdrs = ["network_test_util.hh"],
 | 
			
		||||
    deps = [
 | 
			
		||||
@@ -307,6 +321,7 @@ cc_test(
 | 
			
		||||
    srcs = ["network_test.cc"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":network",
 | 
			
		||||
        ":network_test_util",
 | 
			
		||||
        "@com_google_googletest//:gtest",
 | 
			
		||||
        "@com_google_googletest//:gtest_main",
 | 
			
		||||
    ],
 | 
			
		||||
@@ -341,6 +356,7 @@ cc_test(
 | 
			
		||||
    size = "small",
 | 
			
		||||
    srcs = ["ping_array_test.cc"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":mem_test_util",
 | 
			
		||||
        ":mono_time",
 | 
			
		||||
        ":ping_array",
 | 
			
		||||
        "@com_google_googletest//:gtest",
 | 
			
		||||
@@ -399,6 +415,7 @@ cc_library(
 | 
			
		||||
 | 
			
		||||
cc_library(
 | 
			
		||||
    name = "DHT_test_util",
 | 
			
		||||
    testonly = True,
 | 
			
		||||
    srcs = ["DHT_test_util.cc"],
 | 
			
		||||
    hdrs = ["DHT_test_util.hh"],
 | 
			
		||||
    deps = [
 | 
			
		||||
@@ -418,6 +435,7 @@ cc_test(
 | 
			
		||||
        ":DHT",
 | 
			
		||||
        ":DHT_test_util",
 | 
			
		||||
        ":crypto_core",
 | 
			
		||||
        ":mem_test_util",
 | 
			
		||||
        ":network_test_util",
 | 
			
		||||
        "@com_google_googletest//:gtest",
 | 
			
		||||
        "@com_google_googletest//:gtest_main",
 | 
			
		||||
@@ -468,7 +486,7 @@ cc_fuzz_test(
 | 
			
		||||
    name = "forwarding_fuzz_test",
 | 
			
		||||
    size = "small",
 | 
			
		||||
    srcs = ["forwarding_fuzz_test.cc"],
 | 
			
		||||
    #corpus = ["//tools/toktok-fuzzer/corpus:forwarding_fuzz_test"],
 | 
			
		||||
    corpus = ["//tools/toktok-fuzzer/corpus:forwarding_fuzz_test"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":forwarding",
 | 
			
		||||
        "//c-toxcore/testing/fuzzing:fuzz_support",
 | 
			
		||||
@@ -641,12 +659,26 @@ cc_test(
 | 
			
		||||
    srcs = ["group_announce_test.cc"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":group_announce",
 | 
			
		||||
        ":mem_test_util",
 | 
			
		||||
        ":mono_time",
 | 
			
		||||
        "@com_google_googletest//:gtest",
 | 
			
		||||
        "@com_google_googletest//:gtest_main",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
cc_fuzz_test(
 | 
			
		||||
    name = "group_announce_fuzz_test",
 | 
			
		||||
    size = "small",
 | 
			
		||||
    testonly = True,
 | 
			
		||||
    srcs = ["group_announce_fuzz_test.cc"],
 | 
			
		||||
    corpus = ["//tools/toktok-fuzzer/corpus:group_announce_fuzz_test"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":group_announce",
 | 
			
		||||
        ":mem_test_util",
 | 
			
		||||
        "//c-toxcore/testing/fuzzing:fuzz_support",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
cc_library(
 | 
			
		||||
    name = "group_onion_announce",
 | 
			
		||||
    srcs = ["group_onion_announce.c"],
 | 
			
		||||
@@ -663,17 +695,6 @@ cc_library(
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
cc_fuzz_test(
 | 
			
		||||
    name = "group_announce_fuzz_test",
 | 
			
		||||
    size = "small",
 | 
			
		||||
    srcs = ["group_announce_fuzz_test.cc"],
 | 
			
		||||
    #corpus = ["//tools/toktok-fuzzer/corpus:group_announce_fuzz_test"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":group_announce",
 | 
			
		||||
        "//c-toxcore/testing/fuzzing:fuzz_support",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
cc_library(
 | 
			
		||||
    name = "onion_client",
 | 
			
		||||
    srcs = ["onion_client.c"],
 | 
			
		||||
@@ -759,8 +780,10 @@ cc_test(
 | 
			
		||||
    srcs = ["group_moderation_test.cc"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":crypto_core",
 | 
			
		||||
        ":crypto_core_test_util",
 | 
			
		||||
        ":group_moderation",
 | 
			
		||||
        ":logger",
 | 
			
		||||
        ":mem_test_util",
 | 
			
		||||
        ":util",
 | 
			
		||||
        "@com_google_googletest//:gtest",
 | 
			
		||||
        "@com_google_googletest//:gtest_main",
 | 
			
		||||
@@ -770,10 +793,12 @@ cc_test(
 | 
			
		||||
cc_fuzz_test(
 | 
			
		||||
    name = "group_moderation_fuzz_test",
 | 
			
		||||
    size = "small",
 | 
			
		||||
    testonly = True,
 | 
			
		||||
    srcs = ["group_moderation_fuzz_test.cc"],
 | 
			
		||||
    corpus = ["//tools/toktok-fuzzer/corpus:group_moderation_fuzz_test"],
 | 
			
		||||
    deps = [
 | 
			
		||||
        ":group_moderation",
 | 
			
		||||
        ":mem_test_util",
 | 
			
		||||
        "//c-toxcore/testing/fuzzing:fuzz_support",
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@ void TestHandleRequest(Fuzz_Data &input)
 | 
			
		||||
    uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
 | 
			
		||||
    uint8_t request[MAX_CRYPTO_REQUEST_SIZE];
 | 
			
		||||
    uint8_t request_id;
 | 
			
		||||
    handle_request(
 | 
			
		||||
        self_public_key, self_secret_key, public_key, request, &request_id, input.data, input.size);
 | 
			
		||||
    handle_request(self_public_key, self_secret_key, public_key, request, &request_id, input.data(),
 | 
			
		||||
        input.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestUnpackNodes(Fuzz_Data &input)
 | 
			
		||||
@@ -28,8 +28,8 @@ void TestUnpackNodes(Fuzz_Data &input)
 | 
			
		||||
    const uint16_t node_count = 5;
 | 
			
		||||
    Node_format nodes[node_count];
 | 
			
		||||
    uint16_t processed_data_len;
 | 
			
		||||
    const int packed_count
 | 
			
		||||
        = unpack_nodes(nodes, node_count, &processed_data_len, input.data, input.size, tcp_enabled);
 | 
			
		||||
    const int packed_count = unpack_nodes(
 | 
			
		||||
        nodes, node_count, &processed_data_len, input.data(), input.size(), tcp_enabled);
 | 
			
		||||
    if (packed_count > 0) {
 | 
			
		||||
        Logger *logger = logger_new();
 | 
			
		||||
        std::vector<uint8_t> packed(packed_count * PACKED_NODE_SIZE_IP6);
 | 
			
		||||
@@ -45,8 +45,11 @@ void TestUnpackNodes(Fuzz_Data &input)
 | 
			
		||||
        uint16_t processed_data_len2;
 | 
			
		||||
        const int packed_count2 = unpack_nodes(
 | 
			
		||||
            nodes2, node_count, &processed_data_len2, packed.data(), packed.size(), tcp_enabled);
 | 
			
		||||
        (void)packed_count2;
 | 
			
		||||
#if 0
 | 
			
		||||
        assert(processed_data_len2 == processed_data_len);
 | 
			
		||||
        assert(packed_count2 == packed_count);
 | 
			
		||||
#endif
 | 
			
		||||
        assert(memcmp(nodes, nodes2, sizeof(Node_format) * packed_count) == 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -56,6 +59,6 @@ void TestUnpackNodes(Fuzz_Data &input)
 | 
			
		||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
 | 
			
		||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    fuzz_select_target(data, size, TestHandleRequest, TestUnpackNodes);
 | 
			
		||||
    fuzz_select_target<TestHandleRequest, TestUnpackNodes>(data, size);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
#include "DHT_test_util.hh"
 | 
			
		||||
#include "crypto_core.h"
 | 
			
		||||
#include "crypto_core_test_util.hh"
 | 
			
		||||
#include "mem_test_util.hh"
 | 
			
		||||
#include "network_test_util.hh"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
@@ -326,8 +327,8 @@ TEST(Request, CreateAndParse)
 | 
			
		||||
TEST(AnnounceNodes, SetAndTest)
 | 
			
		||||
{
 | 
			
		||||
    Test_Random rng;
 | 
			
		||||
    const Network *ns = system_network();
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Test_Network ns;
 | 
			
		||||
 | 
			
		||||
    Logger *log = logger_new();
 | 
			
		||||
    ASSERT_NE(log, nullptr);
 | 
			
		||||
 
 | 
			
		||||
@@ -437,14 +437,10 @@ void new_symmetric_key(const Random *rng, uint8_t *key)
 | 
			
		||||
 | 
			
		||||
int32_t crypto_new_keypair(const Random *rng, uint8_t *public_key, uint8_t *secret_key)
 | 
			
		||||
{
 | 
			
		||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
 | 
			
		||||
    random_bytes(rng, secret_key, CRYPTO_SECRET_KEY_SIZE);
 | 
			
		||||
    memset(public_key, 0, CRYPTO_PUBLIC_KEY_SIZE);  // Make MSAN happy
 | 
			
		||||
    crypto_derive_public_key(public_key, secret_key);
 | 
			
		||||
    return 0;
 | 
			
		||||
#else
 | 
			
		||||
    return crypto_box_keypair(public_key, secret_key);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key)
 | 
			
		||||
 
 | 
			
		||||
@@ -89,6 +89,6 @@ void TestForwardReply(Fuzz_Data &input)
 | 
			
		||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
 | 
			
		||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    fuzz_select_target(data, size, TestSendForwardRequest, TestForwardReply);
 | 
			
		||||
    fuzz_select_target<TestSendForwardRequest, TestForwardReply>(data, size);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "../testing/fuzzing/fuzz_support.h"
 | 
			
		||||
#include "mem_test_util.hh"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
@@ -19,7 +20,7 @@ void TestUnpackAnnouncesList(Fuzz_Data &input)
 | 
			
		||||
    CONSUME1_OR_RETURN(const uint16_t, packed_size, input);
 | 
			
		||||
 | 
			
		||||
    Logger *logger = logger_new();
 | 
			
		||||
    if (gca_unpack_announces_list(logger, input.data, input.size, announces.data(), max_count)
 | 
			
		||||
    if (gca_unpack_announces_list(logger, input.data(), input.size(), announces.data(), max_count)
 | 
			
		||||
        != -1) {
 | 
			
		||||
        // Always allocate at least something to avoid passing nullptr to functions below.
 | 
			
		||||
        std::vector<uint8_t> packed(packed_size + 1);
 | 
			
		||||
@@ -38,7 +39,7 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input)
 | 
			
		||||
    CONSUME1_OR_RETURN(const uint16_t, packed_size, input);
 | 
			
		||||
 | 
			
		||||
    Logger *logger = logger_new();
 | 
			
		||||
    if (gca_unpack_public_announce(logger, input.data, input.size, &public_announce) != -1) {
 | 
			
		||||
    if (gca_unpack_public_announce(logger, input.data(), input.size(), &public_announce) != -1) {
 | 
			
		||||
        // Always allocate at least something to avoid passing nullptr to functions below.
 | 
			
		||||
        std::vector<uint8_t> packed(packed_size + 1);
 | 
			
		||||
        gca_pack_public_announce(logger, packed.data(), packed_size, &public_announce);
 | 
			
		||||
@@ -48,19 +49,19 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input)
 | 
			
		||||
 | 
			
		||||
void TestDoGca(Fuzz_Data &input)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    std::unique_ptr<Logger, void (*)(Logger *)> logger(logger_new(), logger_kill);
 | 
			
		||||
    std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time(
 | 
			
		||||
        mono_time_new(mem, nullptr, nullptr), [mem](Mono_Time *ptr) { mono_time_free(mem, ptr); });
 | 
			
		||||
    assert(mono_time != nullptr);
 | 
			
		||||
 | 
			
		||||
    uint64_t clock = 1;
 | 
			
		||||
    mono_time_set_current_time_callback(
 | 
			
		||||
        mono_time.get(), [](void *user_data) { return *static_cast<uint64_t *>(user_data); },
 | 
			
		||||
        &clock);
 | 
			
		||||
    std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time(
 | 
			
		||||
        mono_time_new(
 | 
			
		||||
            mem, [](void *user_data) { return *static_cast<uint64_t *>(user_data); }, &clock),
 | 
			
		||||
        [mem](Mono_Time *ptr) { mono_time_free(mem, ptr); });
 | 
			
		||||
    assert(mono_time != nullptr);
 | 
			
		||||
    std::unique_ptr<GC_Announces_List, void (*)(GC_Announces_List *)> gca(new_gca_list(), kill_gca);
 | 
			
		||||
    assert(gca != nullptr);
 | 
			
		||||
 | 
			
		||||
    while (input.size > 0) {
 | 
			
		||||
    while (!input.empty()) {
 | 
			
		||||
        CONSUME1_OR_RETURN(const uint8_t, choice, input);
 | 
			
		||||
        switch (choice) {
 | 
			
		||||
        case 0: {
 | 
			
		||||
@@ -84,7 +85,8 @@ void TestDoGca(Fuzz_Data &input)
 | 
			
		||||
        case 2: {
 | 
			
		||||
            // Get announces.
 | 
			
		||||
            CONSUME1_OR_RETURN(const uint8_t, max_nodes, input);
 | 
			
		||||
            std::vector<GC_Announce> gc_announces(max_nodes);
 | 
			
		||||
            // Always allocate at least something to avoid passing nullptr to functions below.
 | 
			
		||||
            std::vector<GC_Announce> gc_announces(max_nodes + 1);
 | 
			
		||||
            CONSUME_OR_RETURN(const uint8_t *chat_id, input, CHAT_ID_SIZE);
 | 
			
		||||
            CONSUME_OR_RETURN(const uint8_t *except_public_key, input, ENC_PUBLIC_KEY_SIZE);
 | 
			
		||||
            gca_get_announces(
 | 
			
		||||
@@ -106,6 +108,6 @@ void TestDoGca(Fuzz_Data &input)
 | 
			
		||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
 | 
			
		||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    fuzz_select_target(data, size, TestUnpackAnnouncesList, TestUnpackPublicAnnounce, TestDoGca);
 | 
			
		||||
    fuzz_select_target<TestUnpackAnnouncesList, TestUnpackPublicAnnounce, TestDoGca>(data, size);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,13 +2,14 @@
 | 
			
		||||
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include "mem_test_util.hh"
 | 
			
		||||
#include "mono_time.h"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
struct Announces : ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    const Memory *mem_ = system_memory();
 | 
			
		||||
    Test_Memory mem_;
 | 
			
		||||
    uint64_t clock_ = 1000;
 | 
			
		||||
    Mono_Time *mono_time_ = nullptr;
 | 
			
		||||
    GC_Announces_List *gca_ = nullptr;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								external/toxcore/c-toxcore/toxcore/group_chats.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								external/toxcore/c-toxcore/toxcore/group_chats.c
									
									
									
									
										vendored
									
									
								
							@@ -1442,6 +1442,9 @@ non_null(1, 2, 3, 5, 6) nullable(4)
 | 
			
		||||
static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, uint8_t *data, uint64_t *message_id,
 | 
			
		||||
                               uint8_t *packet_type, const uint8_t *packet, uint16_t length)
 | 
			
		||||
{
 | 
			
		||||
    assert(data != nullptr);
 | 
			
		||||
    assert(packet != nullptr);
 | 
			
		||||
 | 
			
		||||
    if (length <= CRYPTO_NONCE_SIZE) {
 | 
			
		||||
        LOGGER_FATAL(log, "Invalid packet length: %u", length);
 | 
			
		||||
        return -1;
 | 
			
		||||
@@ -4073,17 +4076,11 @@ int gc_founder_set_password(GC_Chat *chat, const uint8_t *password, uint16_t pas
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t *oldpasswd = nullptr;
 | 
			
		||||
    const uint16_t oldlen = chat->shared_state.password_length;
 | 
			
		||||
    uint8_t *oldpasswd = memdup(chat->shared_state.password, oldlen);
 | 
			
		||||
 | 
			
		||||
    if (oldlen > 0) {
 | 
			
		||||
        oldpasswd = (uint8_t *)malloc(oldlen);
 | 
			
		||||
 | 
			
		||||
        if (oldpasswd == nullptr) {
 | 
			
		||||
            return -4;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        memcpy(oldpasswd, chat->shared_state.password, oldlen);
 | 
			
		||||
    if (oldpasswd == nullptr && oldlen > 0) {
 | 
			
		||||
        return -4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!set_gc_password_local(chat, password, password_length)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -101,16 +101,12 @@ static bool create_array_entry(const Logger *log, const Mono_Time *mono_time, GC
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (length == 0) {
 | 
			
		||||
        if (data != nullptr) {
 | 
			
		||||
            LOGGER_FATAL(log, "Got non-null data with zero length (type %d)", packet_type); // should never happen
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        array_entry->data = nullptr;
 | 
			
		||||
        array_entry->data_length = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (data == nullptr) {
 | 
			
		||||
            LOGGER_FATAL(log, "Got null data with non-zero length (type %u)", packet_type); // should never happen
 | 
			
		||||
        if (data == nullptr) {  // should never happen
 | 
			
		||||
            LOGGER_FATAL(log, "Got null data with non-zero length (length: %u, type %u)",
 | 
			
		||||
                         length, packet_type);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,16 @@
 | 
			
		||||
#include "group_moderation.h"
 | 
			
		||||
 | 
			
		||||
#include "../testing/fuzzing/fuzz_support.h"
 | 
			
		||||
#include "mem_test_util.hh"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
void TestModListUnpack(Fuzz_Data &input)
 | 
			
		||||
{
 | 
			
		||||
    CONSUME1_OR_RETURN(const uint16_t, num_mods, input);
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    mod_list_unpack(&mods, input.data, input.size, num_mods);
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    mod_list_unpack(&mods, input.data(), input.size(), num_mods);
 | 
			
		||||
    mod_list_cleanup(&mods);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -17,7 +19,7 @@ void TestSanctionsListUnpack(Fuzz_Data &input)
 | 
			
		||||
    Mod_Sanction sanctions[10];
 | 
			
		||||
    Mod_Sanction_Creds creds;
 | 
			
		||||
    uint16_t processed_data_len;
 | 
			
		||||
    sanctions_list_unpack(sanctions, &creds, 10, input.data, input.size, &processed_data_len);
 | 
			
		||||
    sanctions_list_unpack(sanctions, &creds, 10, input.data(), input.size(), &processed_data_len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestSanctionCredsUnpack(Fuzz_Data &input)
 | 
			
		||||
@@ -32,7 +34,7 @@ void TestSanctionCredsUnpack(Fuzz_Data &input)
 | 
			
		||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
 | 
			
		||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    fuzz_select_target(
 | 
			
		||||
        data, size, TestModListUnpack, TestSanctionsListUnpack, TestSanctionCredsUnpack);
 | 
			
		||||
    fuzz_select_target<TestModListUnpack, TestSanctionsListUnpack, TestSanctionCredsUnpack>(
 | 
			
		||||
        data, size);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,9 @@
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "crypto_core.h"
 | 
			
		||||
#include "crypto_core_test_util.hh"
 | 
			
		||||
#include "logger.h"
 | 
			
		||||
#include "mem_test_util.hh"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
@@ -18,7 +20,8 @@ using ModerationHash = std::array<uint8_t, MOD_MODERATION_HASH_SIZE>;
 | 
			
		||||
 | 
			
		||||
TEST(ModList, PackedSizeOfEmptyModListIsZero)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    EXPECT_EQ(mod_list_packed_size(&mods), 0);
 | 
			
		||||
 | 
			
		||||
    uint8_t byte = 1;
 | 
			
		||||
@@ -28,14 +31,16 @@ TEST(ModList, PackedSizeOfEmptyModListIsZero)
 | 
			
		||||
 | 
			
		||||
TEST(ModList, UnpackingZeroSizeArrayIsNoop)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    const uint8_t byte = 1;
 | 
			
		||||
    EXPECT_EQ(mod_list_unpack(&mods, &byte, 0, 0), 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(ModList, AddRemoveMultipleMods)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    uint8_t sig_pk1[32] = {1};
 | 
			
		||||
    uint8_t sig_pk2[32] = {2};
 | 
			
		||||
    EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk1));
 | 
			
		||||
@@ -47,7 +52,8 @@ TEST(ModList, AddRemoveMultipleMods)
 | 
			
		||||
TEST(ModList, PackingAndUnpackingList)
 | 
			
		||||
{
 | 
			
		||||
    using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>;
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data()));
 | 
			
		||||
 | 
			
		||||
    std::vector<uint8_t> packed(mod_list_packed_size(&mods));
 | 
			
		||||
@@ -55,7 +61,7 @@ TEST(ModList, PackingAndUnpackingList)
 | 
			
		||||
 | 
			
		||||
    EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data()));
 | 
			
		||||
 | 
			
		||||
    Moderation mods2{system_memory()};
 | 
			
		||||
    Moderation mods2{mem};
 | 
			
		||||
    EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 1), packed.size());
 | 
			
		||||
    EXPECT_TRUE(mod_list_remove_entry(&mods2, ModListEntry{}.data()));
 | 
			
		||||
}
 | 
			
		||||
@@ -63,13 +69,14 @@ TEST(ModList, PackingAndUnpackingList)
 | 
			
		||||
TEST(ModList, UnpackingTooManyModsFails)
 | 
			
		||||
{
 | 
			
		||||
    using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>;
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data()));
 | 
			
		||||
 | 
			
		||||
    std::vector<uint8_t> packed(mod_list_packed_size(&mods));
 | 
			
		||||
    mod_list_pack(&mods, packed.data());
 | 
			
		||||
 | 
			
		||||
    Moderation mods2{system_memory()};
 | 
			
		||||
    Moderation mods2{mem};
 | 
			
		||||
    EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 2), -1);
 | 
			
		||||
    EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data()));
 | 
			
		||||
}
 | 
			
		||||
@@ -78,16 +85,17 @@ TEST(ModList, UnpackingFromEmptyBufferFails)
 | 
			
		||||
{
 | 
			
		||||
    std::vector<uint8_t> packed(1);
 | 
			
		||||
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    EXPECT_EQ(mod_list_unpack(&mods, packed.data(), 0, 1), -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(ModList, HashOfEmptyModListZeroesOutBuffer)
 | 
			
		||||
{
 | 
			
		||||
    const Random *rng = system_random();
 | 
			
		||||
    ASSERT_NE(rng, nullptr);
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Test_Random rng;
 | 
			
		||||
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
 | 
			
		||||
    // Fill with random data, check that it's zeroed.
 | 
			
		||||
    ModerationHash hash;
 | 
			
		||||
@@ -98,21 +106,24 @@ TEST(ModList, HashOfEmptyModListZeroesOutBuffer)
 | 
			
		||||
 | 
			
		||||
TEST(ModList, RemoveIndexFromEmptyModListFails)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    EXPECT_FALSE(mod_list_remove_index(&mods, 0));
 | 
			
		||||
    EXPECT_FALSE(mod_list_remove_index(&mods, UINT16_MAX));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(ModList, RemoveEntryFromEmptyModListFails)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    uint8_t sig_pk[32] = {0};
 | 
			
		||||
    EXPECT_FALSE(mod_list_remove_entry(&mods, sig_pk));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(ModList, ModListRemoveIndex)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    uint8_t sig_pk[32] = {1};
 | 
			
		||||
    EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk));
 | 
			
		||||
    EXPECT_TRUE(mod_list_remove_index(&mods, 0));
 | 
			
		||||
@@ -120,20 +131,23 @@ TEST(ModList, ModListRemoveIndex)
 | 
			
		||||
 | 
			
		||||
TEST(ModList, CleanupOnEmptyModsIsNoop)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    mod_list_cleanup(&mods);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(ModList, EmptyModListCannotVerifyAnySigPk)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    uint8_t sig_pk[32] = {1};
 | 
			
		||||
    EXPECT_FALSE(mod_list_verify_sig_pk(&mods, sig_pk));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(ModList, ModListAddVerifyRemoveSigPK)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mods{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods{mem};
 | 
			
		||||
    uint8_t sig_pk[32] = {1};
 | 
			
		||||
    EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk));
 | 
			
		||||
    EXPECT_TRUE(mod_list_verify_sig_pk(&mods, sig_pk));
 | 
			
		||||
@@ -143,7 +157,8 @@ TEST(ModList, ModListAddVerifyRemoveSigPK)
 | 
			
		||||
 | 
			
		||||
TEST(ModList, ModListHashCheck)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mods1{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mods1{mem};
 | 
			
		||||
    uint8_t sig_pk1[32] = {1};
 | 
			
		||||
    std::array<uint8_t, MOD_MODERATION_HASH_SIZE> hash1;
 | 
			
		||||
 | 
			
		||||
@@ -165,7 +180,8 @@ TEST(SanctionsList, PackingIntoUndersizedBufferFails)
 | 
			
		||||
 | 
			
		||||
TEST(SanctionsList, PackUnpackSanctionsCreds)
 | 
			
		||||
{
 | 
			
		||||
    Moderation mod{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mod{mem};
 | 
			
		||||
    std::array<uint8_t, MOD_SANCTIONS_CREDS_SIZE> packed;
 | 
			
		||||
    EXPECT_EQ(sanctions_creds_pack(&mod.sanctions_creds, packed.data()), MOD_SANCTIONS_CREDS_SIZE);
 | 
			
		||||
    EXPECT_EQ(
 | 
			
		||||
@@ -177,7 +193,8 @@ protected:
 | 
			
		||||
    ExtPublicKey pk;
 | 
			
		||||
    ExtSecretKey sk;
 | 
			
		||||
    Logger *log = logger_new();
 | 
			
		||||
    Moderation mod{system_memory()};
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Moderation mod{mem};
 | 
			
		||||
 | 
			
		||||
    Mod_Sanction sanctions[2] = {};
 | 
			
		||||
    const uint8_t sanctioned_pk1[32] = {1};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								external/toxcore/c-toxcore/toxcore/mem_test_util.cc
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								external/toxcore/c-toxcore/toxcore/mem_test_util.cc
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#include "mem_test_util.hh"
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
 | 
			
		||||
Memory_Funcs const Memory_Class::vtable = {
 | 
			
		||||
    Method<mem_malloc_cb, Memory_Class>::invoke<&Memory_Class::malloc>,
 | 
			
		||||
    Method<mem_calloc_cb, Memory_Class>::invoke<&Memory_Class::calloc>,
 | 
			
		||||
    Method<mem_realloc_cb, Memory_Class>::invoke<&Memory_Class::realloc>,
 | 
			
		||||
    Method<mem_free_cb, Memory_Class>::invoke<&Memory_Class::free>,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Memory_Class::~Memory_Class() = default;
 | 
			
		||||
 | 
			
		||||
void *Test_Memory::malloc(void *obj, uint32_t size) { return mem->funcs->malloc(mem->obj, size); }
 | 
			
		||||
 | 
			
		||||
void *Test_Memory::calloc(void *obj, uint32_t nmemb, uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
    return mem->funcs->calloc(mem->obj, nmemb, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *Test_Memory::realloc(void *obj, void *ptr, uint32_t size)
 | 
			
		||||
{
 | 
			
		||||
    return mem->funcs->realloc(mem->obj, ptr, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Test_Memory::free(void *obj, void *ptr) { return mem->funcs->free(mem->obj, ptr); }
 | 
			
		||||
							
								
								
									
										39
									
								
								external/toxcore/c-toxcore/toxcore/mem_test_util.hh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								external/toxcore/c-toxcore/toxcore/mem_test_util.hh
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
#ifndef C_TOXCORE_TOXCORE_MEM_TEST_UTIL_H
 | 
			
		||||
#define C_TOXCORE_TOXCORE_MEM_TEST_UTIL_H
 | 
			
		||||
 | 
			
		||||
#include "mem.h"
 | 
			
		||||
#include "test_util.hh"
 | 
			
		||||
 | 
			
		||||
struct Memory_Class {
 | 
			
		||||
    static Memory_Funcs const vtable;
 | 
			
		||||
    Memory const self;
 | 
			
		||||
 | 
			
		||||
    operator Memory const *() const { return &self; }
 | 
			
		||||
 | 
			
		||||
    Memory_Class(Memory_Class const &) = default;
 | 
			
		||||
    Memory_Class()
 | 
			
		||||
        : self{&vtable, this}
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual ~Memory_Class();
 | 
			
		||||
    virtual mem_malloc_cb malloc = 0;
 | 
			
		||||
    virtual mem_calloc_cb calloc = 0;
 | 
			
		||||
    virtual mem_realloc_cb realloc = 0;
 | 
			
		||||
    virtual mem_free_cb free = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Base test Memory class that just forwards to system_memory. Can be
 | 
			
		||||
 * subclassed to override individual (or all) functions.
 | 
			
		||||
 */
 | 
			
		||||
class Test_Memory : public Memory_Class {
 | 
			
		||||
    const Memory *mem = REQUIRE_NOT_NULL(system_memory());
 | 
			
		||||
 | 
			
		||||
    void *malloc(void *obj, uint32_t size) override;
 | 
			
		||||
    void *calloc(void *obj, uint32_t nmemb, uint32_t size) override;
 | 
			
		||||
    void *realloc(void *obj, void *ptr, uint32_t size) override;
 | 
			
		||||
    void free(void *obj, void *ptr) override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif  // C_TOXCORE_TOXCORE_MEM_TEST_UTIL_H
 | 
			
		||||
@@ -140,7 +140,7 @@ Mono_Time *mono_time_new(const Memory *mem, mono_time_current_time_cb *current_t
 | 
			
		||||
    mono_time->cur_time = 0;
 | 
			
		||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
 | 
			
		||||
    // Maximum reproducibility. Never return time = 0.
 | 
			
		||||
    mono_time->base_time = 1;
 | 
			
		||||
    mono_time->base_time = 1000000000;
 | 
			
		||||
#else
 | 
			
		||||
    // Never return time = 0 in case time() returns 0 (e.g. on microcontrollers
 | 
			
		||||
    // without battery-powered RTC or ones where NTP didn't initialise it yet).
 | 
			
		||||
 
 | 
			
		||||
@@ -5,11 +5,13 @@
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include "mem_test_util.hh"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
TEST(MonoTime, UnixTimeIncreasesOverTime)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
 | 
			
		||||
    ASSERT_NE(mono_time, nullptr);
 | 
			
		||||
 | 
			
		||||
@@ -28,7 +30,7 @@ TEST(MonoTime, UnixTimeIncreasesOverTime)
 | 
			
		||||
 | 
			
		||||
TEST(MonoTime, IsTimeout)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
 | 
			
		||||
    ASSERT_NE(mono_time, nullptr);
 | 
			
		||||
 | 
			
		||||
@@ -46,7 +48,7 @@ TEST(MonoTime, IsTimeout)
 | 
			
		||||
 | 
			
		||||
TEST(MonoTime, IsTimeoutReal)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
 | 
			
		||||
    ASSERT_NE(mono_time, nullptr);
 | 
			
		||||
 | 
			
		||||
@@ -67,7 +69,7 @@ TEST(MonoTime, IsTimeoutReal)
 | 
			
		||||
 | 
			
		||||
TEST(MonoTime, CustomTime)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
 | 
			
		||||
    ASSERT_NE(mono_time, nullptr);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,17 @@
 | 
			
		||||
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include "network_test_util.hh"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
TEST(TestUtil, ProducesNonNullNetwork)
 | 
			
		||||
{
 | 
			
		||||
    Test_Network net;
 | 
			
		||||
    const Network *ns = net;
 | 
			
		||||
    EXPECT_NE(ns, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(IpNtoa, DoesntWriteOutOfBounds)
 | 
			
		||||
{
 | 
			
		||||
    Ip_Ntoa ip_str;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,81 @@
 | 
			
		||||
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
 | 
			
		||||
Network_Funcs const Network_Class::vtable = {
 | 
			
		||||
    Method<net_close_cb, Network_Class>::invoke<&Network_Class::close>,
 | 
			
		||||
    Method<net_accept_cb, Network_Class>::invoke<&Network_Class::accept>,
 | 
			
		||||
    Method<net_bind_cb, Network_Class>::invoke<&Network_Class::bind>,
 | 
			
		||||
    Method<net_listen_cb, Network_Class>::invoke<&Network_Class::listen>,
 | 
			
		||||
    Method<net_recvbuf_cb, Network_Class>::invoke<&Network_Class::recvbuf>,
 | 
			
		||||
    Method<net_recv_cb, Network_Class>::invoke<&Network_Class::recv>,
 | 
			
		||||
    Method<net_recvfrom_cb, Network_Class>::invoke<&Network_Class::recvfrom>,
 | 
			
		||||
    Method<net_send_cb, Network_Class>::invoke<&Network_Class::send>,
 | 
			
		||||
    Method<net_sendto_cb, Network_Class>::invoke<&Network_Class::sendto>,
 | 
			
		||||
    Method<net_socket_cb, Network_Class>::invoke<&Network_Class::socket>,
 | 
			
		||||
    Method<net_socket_nonblock_cb, Network_Class>::invoke<&Network_Class::socket_nonblock>,
 | 
			
		||||
    Method<net_getsockopt_cb, Network_Class>::invoke<&Network_Class::getsockopt>,
 | 
			
		||||
    Method<net_setsockopt_cb, Network_Class>::invoke<&Network_Class::setsockopt>,
 | 
			
		||||
    Method<net_getaddrinfo_cb, Network_Class>::invoke<&Network_Class::getaddrinfo>,
 | 
			
		||||
    Method<net_freeaddrinfo_cb, Network_Class>::invoke<&Network_Class::freeaddrinfo>,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int Test_Network::close(void *obj, int sock) { return net->funcs->close(net->obj, sock); }
 | 
			
		||||
int Test_Network::accept(void *obj, int sock) { return net->funcs->accept(net->obj, sock); }
 | 
			
		||||
int Test_Network::bind(void *obj, int sock, const Network_Addr *addr)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->bind(net->obj, sock, addr);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::listen(void *obj, int sock, int backlog)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->listen(net->obj, sock, backlog);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::recvbuf(void *obj, int sock) { return net->funcs->recvbuf(net->obj, sock); }
 | 
			
		||||
int Test_Network::recv(void *obj, int sock, uint8_t *buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->recv(net->obj, sock, buf, len);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::recvfrom(void *obj, int sock, uint8_t *buf, size_t len, Network_Addr *addr)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->recvfrom(net->obj, sock, buf, len, addr);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::send(void *obj, int sock, const uint8_t *buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->send(net->obj, sock, buf, len);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::sendto(
 | 
			
		||||
    void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->sendto(net->obj, sock, buf, len, addr);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::socket(void *obj, int domain, int type, int proto)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->socket(net->obj, domain, type, proto);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::socket_nonblock(void *obj, int sock, bool nonblock)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->socket_nonblock(net->obj, sock, nonblock);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::getsockopt(
 | 
			
		||||
    void *obj, int sock, int level, int optname, void *optval, size_t *optlen)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->getsockopt(net->obj, sock, level, optname, optval, optlen);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::setsockopt(
 | 
			
		||||
    void *obj, int sock, int level, int optname, const void *optval, size_t optlen)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->setsockopt(net->obj, sock, level, optname, optval, optlen);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::getaddrinfo(void *obj, int family, Network_Addr **addrs)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->getaddrinfo(net->obj, family, addrs);
 | 
			
		||||
}
 | 
			
		||||
int Test_Network::freeaddrinfo(void *obj, Network_Addr *addrs)
 | 
			
		||||
{
 | 
			
		||||
    return net->funcs->freeaddrinfo(net->obj, addrs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Network_Class::~Network_Class() = default;
 | 
			
		||||
 | 
			
		||||
IP_Port increasing_ip_port::operator()()
 | 
			
		||||
{
 | 
			
		||||
    IP_Port ip_port;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,60 @@
 | 
			
		||||
#include "network.h"
 | 
			
		||||
#include "test_util.hh"
 | 
			
		||||
 | 
			
		||||
struct Network_Class {
 | 
			
		||||
    static Network_Funcs const vtable;
 | 
			
		||||
    Network const self;
 | 
			
		||||
 | 
			
		||||
    operator Network const *() const { return &self; }
 | 
			
		||||
 | 
			
		||||
    Network_Class(Network_Class const &) = default;
 | 
			
		||||
    Network_Class()
 | 
			
		||||
        : self{&vtable, this}
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual ~Network_Class();
 | 
			
		||||
    virtual net_close_cb close = 0;
 | 
			
		||||
    virtual net_accept_cb accept = 0;
 | 
			
		||||
    virtual net_bind_cb bind = 0;
 | 
			
		||||
    virtual net_listen_cb listen = 0;
 | 
			
		||||
    virtual net_recvbuf_cb recvbuf = 0;
 | 
			
		||||
    virtual net_recv_cb recv = 0;
 | 
			
		||||
    virtual net_recvfrom_cb recvfrom = 0;
 | 
			
		||||
    virtual net_send_cb send = 0;
 | 
			
		||||
    virtual net_sendto_cb sendto = 0;
 | 
			
		||||
    virtual net_socket_cb socket = 0;
 | 
			
		||||
    virtual net_socket_nonblock_cb socket_nonblock = 0;
 | 
			
		||||
    virtual net_getsockopt_cb getsockopt = 0;
 | 
			
		||||
    virtual net_setsockopt_cb setsockopt = 0;
 | 
			
		||||
    virtual net_getaddrinfo_cb getaddrinfo = 0;
 | 
			
		||||
    virtual net_freeaddrinfo_cb freeaddrinfo = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Base test Network class that just forwards to system_network. Can be
 | 
			
		||||
 * subclassed to override individual (or all) functions.
 | 
			
		||||
 */
 | 
			
		||||
class Test_Network : public Network_Class {
 | 
			
		||||
    const Network *net = REQUIRE_NOT_NULL(system_network());
 | 
			
		||||
 | 
			
		||||
    int close(void *obj, int sock) override;
 | 
			
		||||
    int accept(void *obj, int sock) override;
 | 
			
		||||
    int bind(void *obj, int sock, const Network_Addr *addr) override;
 | 
			
		||||
    int listen(void *obj, int sock, int backlog) override;
 | 
			
		||||
    int recvbuf(void *obj, int sock) override;
 | 
			
		||||
    int recv(void *obj, int sock, uint8_t *buf, size_t len) override;
 | 
			
		||||
    int recvfrom(void *obj, int sock, uint8_t *buf, size_t len, Network_Addr *addr) override;
 | 
			
		||||
    int send(void *obj, int sock, const uint8_t *buf, size_t len) override;
 | 
			
		||||
    int sendto(void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) override;
 | 
			
		||||
    int socket(void *obj, int domain, int type, int proto) override;
 | 
			
		||||
    int socket_nonblock(void *obj, int sock, bool nonblock) override;
 | 
			
		||||
    int getsockopt(void *obj, int sock, int level, int optname, void *optval, size_t *optlen) override;
 | 
			
		||||
    int setsockopt(void *obj, int sock, int level, int optname, const void *optval, size_t optlen) override;
 | 
			
		||||
    int getaddrinfo(void *obj, int family, Network_Addr **addrs) override;
 | 
			
		||||
    int freeaddrinfo(void *obj, Network_Addr *addrs) override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Deleter<Networking_Core> : Function_Deleter<Networking_Core, kill_networking> { };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "mem_test_util.hh"
 | 
			
		||||
#include "mono_time.h"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
@@ -15,7 +16,7 @@ struct Ping_Array_Deleter {
 | 
			
		||||
using Ping_Array_Ptr = std::unique_ptr<Ping_Array, Ping_Array_Deleter>;
 | 
			
		||||
 | 
			
		||||
struct Mono_Time_Deleter {
 | 
			
		||||
    Mono_Time_Deleter(const Memory *mem)
 | 
			
		||||
    Mono_Time_Deleter(const Test_Memory &mem)
 | 
			
		||||
        : mem_(mem)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
@@ -29,21 +30,21 @@ using Mono_Time_Ptr = std::unique_ptr<Mono_Time, Mono_Time_Deleter>;
 | 
			
		||||
 | 
			
		||||
TEST(PingArray, MinimumTimeoutIsOne)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    EXPECT_EQ(ping_array_new(mem, 1, 0), nullptr);
 | 
			
		||||
    EXPECT_NE(Ping_Array_Ptr(ping_array_new(mem, 1, 1)), nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(PingArray, MinimumArraySizeIsOne)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
    EXPECT_EQ(ping_array_new(mem, 0, 1), nullptr);
 | 
			
		||||
    EXPECT_NE(Ping_Array_Ptr(ping_array_new(mem, 1, 1)), nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(PingArray, ArraySizeMustBePowerOfTwo)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
 | 
			
		||||
    Ping_Array_Ptr arr;
 | 
			
		||||
    arr.reset(ping_array_new(mem, 2, 1));
 | 
			
		||||
@@ -59,7 +60,7 @@ TEST(PingArray, ArraySizeMustBePowerOfTwo)
 | 
			
		||||
 | 
			
		||||
TEST(PingArray, StoredDataCanBeRetrieved)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
 | 
			
		||||
    Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
 | 
			
		||||
    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
 | 
			
		||||
@@ -78,7 +79,7 @@ TEST(PingArray, StoredDataCanBeRetrieved)
 | 
			
		||||
 | 
			
		||||
TEST(PingArray, RetrievingDataWithTooSmallOutputBufferHasNoEffect)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
 | 
			
		||||
    Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
 | 
			
		||||
    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
 | 
			
		||||
@@ -101,7 +102,7 @@ TEST(PingArray, RetrievingDataWithTooSmallOutputBufferHasNoEffect)
 | 
			
		||||
 | 
			
		||||
TEST(PingArray, ZeroLengthDataCanBeAdded)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
 | 
			
		||||
    Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
 | 
			
		||||
    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
 | 
			
		||||
@@ -118,7 +119,7 @@ TEST(PingArray, ZeroLengthDataCanBeAdded)
 | 
			
		||||
 | 
			
		||||
TEST(PingArray, PingId0IsInvalid)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
 | 
			
		||||
    Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
 | 
			
		||||
    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
 | 
			
		||||
@@ -131,7 +132,7 @@ TEST(PingArray, PingId0IsInvalid)
 | 
			
		||||
// Protection against replay attacks.
 | 
			
		||||
TEST(PingArray, DataCanOnlyBeRetrievedOnce)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
 | 
			
		||||
    Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
 | 
			
		||||
    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
 | 
			
		||||
@@ -149,7 +150,7 @@ TEST(PingArray, DataCanOnlyBeRetrievedOnce)
 | 
			
		||||
 | 
			
		||||
TEST(PingArray, PingIdMustMatchOnCheck)
 | 
			
		||||
{
 | 
			
		||||
    const Memory *mem = system_memory();
 | 
			
		||||
    Test_Memory mem;
 | 
			
		||||
 | 
			
		||||
    Ping_Array_Ptr const arr(ping_array_new(mem, 1, 1));
 | 
			
		||||
    Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								external/toxcore/c-toxcore/toxcore/test_util.hh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								external/toxcore/c-toxcore/toxcore/test_util.hh
									
									
									
									
										vendored
									
									
								
							@@ -3,7 +3,10 @@
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
template <typename T, void (*Delete)(T *)>
 | 
			
		||||
@@ -41,7 +44,7 @@ std::array<T, N> to_array(T const (&arr)[N])
 | 
			
		||||
template <std::size_t N, typename T, typename... Args>
 | 
			
		||||
auto array_of(T &&make, Args... args)
 | 
			
		||||
{
 | 
			
		||||
    std::array<typename std::result_of<T(Args...)>::type, N> arr;
 | 
			
		||||
    std::array<std::invoke_result_t<T, Args...>, N> arr;
 | 
			
		||||
    for (auto &elem : arr) {
 | 
			
		||||
        elem = make(args...);
 | 
			
		||||
    }
 | 
			
		||||
@@ -51,7 +54,7 @@ auto array_of(T &&make, Args... args)
 | 
			
		||||
template <typename T, typename... Args>
 | 
			
		||||
auto vector_of(std::size_t n, T &&make, Args... args)
 | 
			
		||||
{
 | 
			
		||||
    std::vector<typename std::result_of<T(Args...)>::type> vec;
 | 
			
		||||
    std::vector<std::invoke_result_t<T, Args...>> vec;
 | 
			
		||||
    for (std::size_t i = 0; i < n; ++i) {
 | 
			
		||||
        vec.push_back(make(args...));
 | 
			
		||||
    }
 | 
			
		||||
@@ -65,4 +68,16 @@ Container sorted(Container arr, Less less)
 | 
			
		||||
    return arr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
T *require_not_null(const char *file, int line, T *ptr)
 | 
			
		||||
{
 | 
			
		||||
    if (ptr == nullptr) {
 | 
			
		||||
        std::fprintf(stderr, "unexpected null pointer at %s:%d\n", file, line);
 | 
			
		||||
        std::exit(7);
 | 
			
		||||
    }
 | 
			
		||||
    return ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define REQUIRE_NOT_NULL(ptr) require_not_null(__FILE__, __LINE__, ptr)
 | 
			
		||||
 | 
			
		||||
#endif  // C_TOXCORE_TOXCORE_TEST_UTIL_H
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ void TestUnpack(Fuzz_Data data)
 | 
			
		||||
    // events_size bytes: events data (max 64K)
 | 
			
		||||
    CONSUME_OR_RETURN(const uint8_t *events_data, data, events_size);
 | 
			
		||||
 | 
			
		||||
    if (data.size == 0) {
 | 
			
		||||
    if (data.empty()) {
 | 
			
		||||
        // If there's no more input, no malloc failure paths can possibly be
 | 
			
		||||
        // tested, so we ignore this input.
 | 
			
		||||
        return;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								external/toxcore/c-toxcore/toxcore/util.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								external/toxcore/c-toxcore/toxcore/util.c
									
									
									
									
										vendored
									
									
								
							@@ -13,6 +13,7 @@
 | 
			
		||||
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "ccompat.h"
 | 
			
		||||
@@ -80,6 +81,21 @@ bool memeq(const uint8_t *a, size_t a_size, const uint8_t *b, size_t b_size)
 | 
			
		||||
    return a_size == b_size && memcmp(a, b, a_size) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t *memdup(const uint8_t *data, size_t data_size)
 | 
			
		||||
{
 | 
			
		||||
    if (data == nullptr || data_size == 0) {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint8_t *copy = (uint8_t *)malloc(data_size);
 | 
			
		||||
 | 
			
		||||
    if (copy != nullptr) {
 | 
			
		||||
        memcpy(copy, data, data_size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return copy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int16_t max_s16(int16_t a, int16_t b)
 | 
			
		||||
{
 | 
			
		||||
    return a > b ? a : b;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								external/toxcore/c-toxcore/toxcore/util.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								external/toxcore/c-toxcore/toxcore/util.h
									
									
									
									
										vendored
									
									
								
							@@ -41,6 +41,13 @@ non_null() int create_recursive_mutex(pthread_mutex_t *mutex);
 | 
			
		||||
 */
 | 
			
		||||
non_null() bool memeq(const uint8_t *a, size_t a_size, const uint8_t *b, size_t b_size);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Copies a byte array of a given size into a newly allocated one.
 | 
			
		||||
 *
 | 
			
		||||
 * @return nullptr on allocation failure or if the input data was nullptr or data_size was 0.
 | 
			
		||||
 */
 | 
			
		||||
nullable(1) uint8_t *memdup(const uint8_t *data, size_t data_size);
 | 
			
		||||
 | 
			
		||||
// Safe min/max functions with specific types. This forces the conversion to the
 | 
			
		||||
// desired type before the comparison expression, giving the choice of
 | 
			
		||||
// conversion to the caller. Use these instead of inline comparisons or MIN/MAX
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user