Compare commits

..

No commits in common. "2f44996edcaf77369c81aa0dab8521b75d8b6793" and "565aa4b7eb9f546b8a6dc4177b5c5a8c663c7ab5" have entirely different histories.

41 changed files with 306 additions and 782 deletions

View File

@ -1,6 +1,6 @@
#!/bin/bash -eu #!/bin/bash -eu
FUZZ_TARGETS="bootstrap_fuzz_test toxsave_fuzz_test" FUZZ_TARGETS="bootstrap_fuzzer toxsave_fuzzer"
# out of tree build # out of tree build
cd "$WORK" cd "$WORK"

View File

@ -501,8 +501,6 @@ add_library(test_util STATIC
toxcore/DHT_test_util.hh toxcore/DHT_test_util.hh
toxcore/crypto_core_test_util.cc toxcore/crypto_core_test_util.cc
toxcore/crypto_core_test_util.hh 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.cc
toxcore/network_test_util.hh toxcore/network_test_util.hh
toxcore/test_util.cc toxcore/test_util.cc

View File

@ -1 +1 @@
5061f92a95ba45cfa49d78175fa8fb6e4d66a58d86634ea3fd3ae6d80cb0558a /usr/local/bin/tox-bootstrapd 08fe68095b88c142e0c7f3369c5f297f1377e219d0e0f0ff6f30ca94d76fca98 /usr/local/bin/tox-bootstrapd

View File

@ -4,4 +4,4 @@
cd ../ cd ../
# Run code coverage only on minized corpus to save time # Run code coverage only on minized corpus to save time
afl-cov --cover-corpus -d ./_afl_out --overwrite --live --coverage-cmd "_cov_build/bootstrap_fuzz_test @@" --code-dir ../ afl-cov --cover-corpus -d ./_afl_out --overwrite --live --coverage-cmd "_cov_build/bootstrap_fuzzer @@" --code-dir ../

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
HARNESS_BIN="../_afl_build/bootstrap_fuzz_test" HARNESS_BIN="../_afl_build/bootstrap_fuzzer"
COV_BIN="../_cov_build/bootstrap_fuzz_test" COV_BIN="../_cov_build/bootstrap_fuzzer"
# move to repo root # move to repo root
cd ../ cd ../

View File

@ -1,5 +1,6 @@
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_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( cc_library(
name = "fuzz_support", name = "fuzz_support",
@ -26,9 +27,9 @@ cc_library(
cc_fuzz_test( cc_fuzz_test(
name = "bootstrap_fuzz_test", name = "bootstrap_fuzz_test",
size = "small", size = "small",
srcs = ["bootstrap_fuzz_test.cc"], srcs = ["bootstrap_harness.cc"],
copts = ["-UNDEBUG"], copts = ["-UNDEBUG"],
corpus = ["//tools/toktok-fuzzer/corpus:bootstrap_fuzz_test"], corpus = ["//tools/toktok-fuzzer/corpus:bootstrap_fuzzer"],
deps = [ deps = [
":fuzz_support", ":fuzz_support",
":fuzz_tox", ":fuzz_tox",
@ -57,9 +58,9 @@ cc_fuzz_test(
cc_fuzz_test( cc_fuzz_test(
name = "toxsave_fuzz_test", name = "toxsave_fuzz_test",
size = "small", size = "small",
srcs = ["toxsave_fuzz_test.cc"], srcs = ["toxsave_harness.cc"],
copts = ["-UNDEBUG"], copts = ["-UNDEBUG"],
corpus = ["//tools/toktok-fuzzer/corpus:toxsave_fuzz_test"], corpus = ["//tools/toktok-fuzzer/corpus:toxsave_fuzzer"],
deps = [ deps = [
":fuzz_support", ":fuzz_support",
"//c-toxcore/toxcore:tox", "//c-toxcore/toxcore:tox",
@ -79,34 +80,12 @@ cc_binary(
], ],
) )
genrule( fuzzing_binary(
name = "e2e_fuzz_test_init", name = "protodump_bin",
outs = [ testonly = True,
"e2e_fuzz_test_init.dat", binary = ":protodump",
"e2e_fuzz_test_bootstrap.dat", engine = "@rules_fuzzing//fuzzing:cc_engine",
],
cmd = "$(location :protodump) $(location e2e_fuzz_test_init.dat) $(location e2e_fuzz_test_bootstrap.dat)",
tags = ["manual"], 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( cc_fuzz_test(

View File

@ -9,18 +9,22 @@ else()
endif() endif()
function(fuzz_test target source_dir) function(fuzz_test target source_dir)
set(CORPUS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/toktok-fuzzer/corpus/${target}_fuzz_test) set(${target}_CORPUS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/toktok-fuzzer/corpus/${target}_fuzz_test)
file(GLOB CORPUS "${CORPUS_DIR}/*") file(GLOB ${target}_fuzz_CORPUS "${${target}_CORPUS_DIR}/*")
add_executable(${target}_fuzz_test ${source_dir}/${target}_fuzz_test.cc) add_executable(${target}_fuzz_test ${source_dir}/${target}_fuzz_test.cc)
target_link_libraries(${target}_fuzz_test PRIVATE fuzz_support test_util toxcore_fuzz ${LIBFUZZER_LINKER_FLAGS}) target_link_libraries(${target}_fuzz_test PRIVATE toxcore_fuzz fuzz_support ${LIBFUZZER_LINKER_FLAGS})
if(CORPUS) if(${target}_fuzz_CORPUS)
add_test(NAME ${target}_fuzz COMMAND ${CROSSCOMPILING_EMULATOR} ${target}_fuzz_test -max_total_time=10 ${CORPUS}) add_test(NAME ${target}_fuzz COMMAND ${CROSSCOMPILING_EMULATOR} ${target}_fuzz_test -max_total_time=10 ${${target}_fuzz_CORPUS})
set_property(TEST ${target}_fuzz PROPERTY ENVIRONMENT "LLVM_PROFILE_FILE=${target}.profraw;srcdir=${CMAKE_CURRENT_SOURCE_DIR}")
endif() endif()
endfunction() endfunction()
fuzz_test(bootstrap .) # Fuzzes the bootstrap process # Fuzzes the toxsave API
fuzz_test(toxsave .) # Fuzzes the bootstrap process 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(DHT ../../toxcore) fuzz_test(DHT ../../toxcore)
fuzz_test(forwarding ../../toxcore) fuzz_test(forwarding ../../toxcore)

View File

@ -83,12 +83,9 @@ void setup_callbacks(Tox_Dispatch *dispatch)
dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) {
Tox_Err_Friend_Add err; Tox_Err_Friend_Add err;
tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &err); tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &err);
if (!(err == TOX_ERR_FRIEND_ADD_OK || err == TOX_ERR_FRIEND_ADD_OWN_KEY 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_ALREADY_SENT
|| err == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM || 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( tox_events_callback_friend_status(
dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) {
@ -123,7 +120,7 @@ void TestBootstrap(Fuzz_Data &input)
[](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func, [](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
const char *message, void *user_data) { const char *message, void *user_data) {
// Log to stdout. // Log to stdout.
if (Fuzz_Data::DEBUG) { if (DEBUG) {
std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line, std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
func, message); func, message);
} }
@ -170,7 +167,7 @@ void TestBootstrap(Fuzz_Data &input)
assert(dispatch != nullptr); assert(dispatch != nullptr);
setup_callbacks(dispatch); setup_callbacks(dispatch);
while (!input.empty()) { while (input.size > 0) {
Tox_Err_Events_Iterate error_iterate; Tox_Err_Events_Iterate error_iterate;
Tox_Events *events = tox_events_iterate(tox, true, &error_iterate); Tox_Events *events = tox_events_iterate(tox, true, &error_iterate);
assert(tox_events_equal(null_sys.sys.get(), events, events)); assert(tox_events_equal(null_sys.sys.get(), events, events));

View File

@ -110,6 +110,9 @@ void setup_callbacks(Tox_Dispatch *dispatch)
dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) {
Tox_Err_Friend_Add err; Tox_Err_Friend_Add err;
tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &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( tox_events_callback_friend_status(
dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) {
@ -144,7 +147,7 @@ void TestEndToEnd(Fuzz_Data &input)
[](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func, [](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
const char *message, void *user_data) { const char *message, void *user_data) {
// Log to stdout. // Log to stdout.
if (Fuzz_Data::DEBUG) { if (DEBUG) {
std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line, std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
func, message); func, message);
} }
@ -167,7 +170,7 @@ void TestEndToEnd(Fuzz_Data &input)
assert(dispatch != nullptr); assert(dispatch != nullptr);
setup_callbacks(dispatch); setup_callbacks(dispatch);
while (!input.empty()) { while (input.size > 0) {
Tox_Err_Events_Iterate error_iterate; Tox_Err_Events_Iterate error_iterate;
Tox_Events *events = tox_events_iterate(tox, true, &error_iterate); Tox_Events *events = tox_events_iterate(tox, true, &error_iterate);
assert(tox_events_equal(null_sys.sys.get(), events, events)); assert(tox_events_equal(null_sys.sys.get(), events, events));

View File

@ -20,6 +20,10 @@
#include "../../toxcore/tox_private.h" #include "../../toxcore/tox_private.h"
#include "func_conversion.h" #include "func_conversion.h"
const bool DEBUG = false;
static constexpr tox_mono_time_cb *get_self_clock = ![](Fuzz_System *self) { return self->clock; };
// TODO(iphydf): Put this somewhere shared. // TODO(iphydf): Put this somewhere shared.
struct Network_Addr { struct Network_Addr {
struct sockaddr_storage addr; struct sockaddr_storage addr;
@ -40,67 +44,58 @@ System::~System() { }
static int recv_common(Fuzz_Data &input, uint8_t *buf, size_t buf_len) static int recv_common(Fuzz_Data &input, uint8_t *buf, size_t buf_len)
{ {
if (input.size() < 2) { if (input.size < 2) {
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
CONSUME_OR_ABORT(const uint8_t *fuzz_len_bytes, input, 2); const size_t fuzz_len = (input.data[0] << 8) | input.data[1];
const std::size_t fuzz_len = (fuzz_len_bytes[0] << 8) | fuzz_len_bytes[1]; input.data += 2;
input.size -= 2;
if (fuzz_len == 0xffff) { if (fuzz_len == 0xffff) {
errno = EWOULDBLOCK; errno = EWOULDBLOCK;
if (Fuzz_Data::DEBUG) { if (DEBUG) {
std::printf("recvfrom: no data for tox1\n"); std::printf("recvfrom: no data for tox1\n");
} }
return -1; return -1;
} }
if (Fuzz_Data::DEBUG) { if (DEBUG) {
std::printf( 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));
CONSUME_OR_ABORT(const uint8_t *data, input, res); std::copy(input.data, input.data + res, buf);
std::copy(data, data + res, buf); input.data += res;
input.size -= res;
return res; return res;
} }
static void *report_alloc(const char *name, const char *func, std::size_t size, void *ptr) template <typename F>
static void *alloc_common(Fuzz_Data &data, F func)
{ {
if (Fuzz_Data::DEBUG) { CONSUME1_OR_RETURN_VAL(const uint8_t, want_alloc, data, func());
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) { if (!want_alloc) {
return nullptr; return nullptr;
} }
return report_alloc("tox1", func, size, Func(args...)); return func();
} }
static constexpr Memory_Funcs fuzz_memory_funcs = { static constexpr Memory_Funcs fuzz_memory_funcs = {
/* .malloc = */ /* .malloc = */
![](Fuzz_System *self, uint32_t size) { ![](Fuzz_System *self, uint32_t size) {
return alloc_common<decltype(std::malloc), std::malloc>("malloc", size, self->data, size); return alloc_common(self->data, [=]() { return std::malloc(size); });
}, },
/* .calloc = */ /* .calloc = */
![](Fuzz_System *self, uint32_t nmemb, uint32_t size) { ![](Fuzz_System *self, uint32_t nmemb, uint32_t size) {
return alloc_common<decltype(std::calloc), std::calloc>( return alloc_common(self->data, [=]() { return std::calloc(nmemb, size); });
"calloc", nmemb * size, self->data, nmemb, size);
}, },
/* .realloc = */ /* .realloc = */
![](Fuzz_System *self, void *ptr, uint32_t size) { ![](Fuzz_System *self, void *ptr, uint32_t size) {
return alloc_common<decltype(std::realloc), std::realloc>( return alloc_common(self->data, [=]() { return std::realloc(ptr, size); });
"realloc", size, self->data, ptr, size);
}, },
/* .free = */ /* .free = */
![](Fuzz_System *self, void *ptr) { std::free(ptr); }, ![](Fuzz_System *self, void *ptr) { std::free(ptr); },
@ -115,7 +110,7 @@ static constexpr Network_Funcs fuzz_network_funcs = {
![](Fuzz_System *self, int sock) { ![](Fuzz_System *self, int sock) {
assert(sock == 42 || sock == 1337); assert(sock == 42 || sock == 1337);
const size_t count = random_u16(self->rng.get()); 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 = */ /* .recv = */
![](Fuzz_System *self, int sock, uint8_t *buf, size_t len) { ![](Fuzz_System *self, int sock, uint8_t *buf, size_t len) {
@ -168,17 +163,14 @@ static constexpr Random_Funcs fuzz_random_funcs = {
/* .random_bytes = */ /* .random_bytes = */
![](Fuzz_System *self, uint8_t *bytes, size_t length) { ![](Fuzz_System *self, uint8_t *bytes, size_t length) {
// Amount of data is limited // 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 // Initialize everything to make MSAN and others happy
std::memset(bytes, 0, length); std::memset(bytes, 0, length);
CONSUME_OR_ABORT(const uint8_t *data, self->data, bytes_read); std::copy(self->data.data, self->data.data + bytes_read, bytes);
std::copy(data, data + bytes_read, bytes); self->data.data += bytes_read;
if (Fuzz_Data::DEBUG) { self->data.size -= bytes_read;
if (length == 1) { if (DEBUG) {
std::printf("rng: %d (0x%02x)\n", bytes[0], bytes[0]); std::printf("rng: %02x..%02x[%zu] -> tox1\n", bytes[0], bytes[length - 1], length);
} else {
std::printf("rng: %02x..%02x[%zu]\n", bytes[0], bytes[length - 1], length);
}
} }
}, },
/* .random_uniform = */ /* .random_uniform = */
@ -202,7 +194,7 @@ Fuzz_System::Fuzz_System(Fuzz_Data &input)
} }
, data(input) , data(input)
{ {
sys->mono_time_callback = [](void *self) { return static_cast<Fuzz_System *>(self)->clock; }; sys->mono_time_callback = get_self_clock;
sys->mono_time_user_data = this; sys->mono_time_user_data = this;
sys->mem = mem.get(); sys->mem = mem.get();
sys->ns = ns.get(); sys->ns = ns.get();
@ -289,7 +281,7 @@ Null_System::Null_System()
std::make_unique<Random>(Random{&null_random_funcs, this}), std::make_unique<Random>(Random{&null_random_funcs, this}),
} }
{ {
sys->mono_time_callback = [](void *self) { return static_cast<Null_System *>(self)->clock; }; sys->mono_time_callback = get_self_clock;
sys->mono_time_user_data = this; sys->mono_time_user_data = this;
sys->mem = mem.get(); sys->mem = mem.get();
sys->ns = ns.get(); sys->ns = ns.get();
@ -306,25 +298,7 @@ static uint16_t get_port(const Network_Addr *addr)
} }
} }
static constexpr Memory_Funcs record_memory_funcs = { static constexpr Memory_Funcs record_memory_funcs = null_memory_funcs;
/* .malloc = */
![](Record_System *self, uint32_t size) {
self->push(true);
return report_alloc(self->name_, "malloc", size, std::malloc(size));
},
/* .calloc = */
![](Record_System *self, uint32_t nmemb, uint32_t size) {
self->push(true);
return report_alloc(self->name_, "calloc", nmemb * size, std::calloc(nmemb, size));
},
/* .realloc = */
![](Record_System *self, void *ptr, uint32_t size) {
self->push(true);
return report_alloc(self->name_, "realloc", size, std::realloc(ptr, size));
},
/* .free = */
![](Record_System *self, void *ptr) { std::free(ptr); },
};
static constexpr Network_Funcs record_network_funcs = { static constexpr Network_Funcs record_network_funcs = {
/* .close = */ ![](Record_System *self, int sock) { return 0; }, /* .close = */ ![](Record_System *self, int sock) { return 0; },
@ -352,10 +326,11 @@ static constexpr Network_Funcs record_network_funcs = {
![](Record_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) { ![](Record_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) {
assert(sock == 42); assert(sock == 42);
if (self->recvq.empty()) { if (self->recvq.empty()) {
self->push("\xff\xff"); self->recording.push_back(0xff);
self->recording.push_back(0xff);
errno = EWOULDBLOCK; errno = EWOULDBLOCK;
if (Fuzz_Data::DEBUG) { if (DEBUG) {
std::printf("%s: recvfrom: no data\n", self->name_); std::printf("recvfrom: no data for %s\n", self->name_);
} }
return -1; return -1;
} }
@ -375,13 +350,13 @@ static constexpr Network_Funcs record_network_funcs = {
addr->size = sizeof(struct sockaddr); addr->size = sizeof(struct sockaddr);
assert(recvlen > 0 && recvlen <= INT_MAX); assert(recvlen > 0 && recvlen <= INT_MAX);
self->push(uint8_t(recvlen >> 8)); self->recording.push_back(recvlen >> 8);
self->push(uint8_t(recvlen & 0xff)); self->recording.push_back(recvlen & 0xff);
if (Fuzz_Data::DEBUG) { if (DEBUG) {
std::printf("%s: recvfrom: %zu (%02x, %02x)\n", self->name_, recvlen, std::printf("recvfrom: %zu (%02x, %02x) for %s\n", recvlen, self->recording.end()[-2],
self->recording().end()[-2], self->recording().end()[-1]); self->recording.end()[-1], self->name_);
} }
self->push(buf, recvlen); self->recording.insert(self->recording.end(), buf, buf + recvlen);
return static_cast<int>(recvlen); return static_cast<int>(recvlen);
}, },
/* .send = */ /* .send = */
@ -415,11 +390,11 @@ static constexpr Random_Funcs record_random_funcs = {
![](Record_System *self, uint8_t *bytes, size_t length) { ![](Record_System *self, uint8_t *bytes, size_t length) {
for (size_t i = 0; i < length; ++i) { for (size_t i = 0; i < length; ++i) {
bytes[i] = simple_rng(self->seed_) & 0xff; bytes[i] = simple_rng(self->seed_) & 0xff;
self->push(bytes[i]); self->recording.push_back(bytes[i]);
} }
if (Fuzz_Data::DEBUG) { if (DEBUG) {
std::printf( std::printf(
"%s: rng: %02x..%02x[%zu]\n", self->name_, bytes[0], bytes[length - 1], length); "rng: %02x..%02x[%zu] -> %s\n", bytes[0], bytes[length - 1], length, self->name_);
} }
}, },
/* .random_uniform = */ /* .random_uniform = */
@ -437,7 +412,7 @@ Record_System::Record_System(Global &global, uint64_t seed, const char *name)
, seed_(seed) , seed_(seed)
, name_(name) , name_(name)
{ {
sys->mono_time_callback = [](void *self) { return static_cast<Record_System *>(self)->clock; }; sys->mono_time_callback = get_self_clock;
sys->mono_time_user_data = this; sys->mono_time_user_data = this;
sys->mem = mem.get(); sys->mem = mem.get();
sys->ns = ns.get(); sys->ns = ns.get();

View File

@ -6,7 +6,6 @@
#define C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H #define C_TOXCORE_TESTING_FUZZING_FUZZ_SUPPORT_H
#include <cstdint> #include <cstdint>
#include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <deque> #include <deque>
@ -18,19 +17,12 @@
#include "../../toxcore/tox.h" #include "../../toxcore/tox.h"
struct Fuzz_Data { struct Fuzz_Data {
static constexpr bool DEBUG = false; const uint8_t *data;
static constexpr std::size_t TRACE_TRAP = -1; // 579; std::size_t size;
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) Fuzz_Data(const uint8_t *input_data, std::size_t input_size)
: data_(input_data) : data(input_data)
, base_(input_data) , size(input_size)
, size_(input_size)
{ {
} }
@ -38,54 +30,25 @@ public:
Fuzz_Data(const Fuzz_Data &rhs) = delete; Fuzz_Data(const Fuzz_Data &rhs) = delete;
struct Consumer { struct Consumer {
const char *func;
Fuzz_Data &fd; 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> template <typename T>
operator T() operator T()
{ {
const uint8_t *bytes = fd.consume(func, sizeof(T)); const uint8_t *bytes = fd.consume(sizeof(T));
T val; T val;
std::memcpy(&val, bytes, sizeof(T)); std::memcpy(&val, bytes, sizeof(T));
return val; return val;
} }
}; };
Consumer consume1(const char *func) { return Consumer{func, *this}; } Consumer consume1() { return Consumer{*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(const char *func, std::size_t count) const uint8_t *consume(std::size_t count)
{ {
const uint8_t *val = data_; const uint8_t *val = data;
if (DEBUG) { data += count;
if (pos() == TRACE_TRAP) { size -= count;
__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; return val;
} }
}; };
@ -101,10 +64,10 @@ public:
* @endcode * @endcode
*/ */
#define CONSUME1_OR_RETURN(TYPE, NAME, INPUT) \ #define CONSUME1_OR_RETURN(TYPE, NAME, INPUT) \
if (INPUT.size() < sizeof(TYPE)) { \ if (INPUT.size < sizeof(TYPE)) { \
return; \ return; \
} \ } \
TYPE NAME = INPUT.consume1(__func__) TYPE NAME = INPUT.consume1()
/** @brief Consumes 1 byte of the fuzzer input or returns a value if no data /** @brief Consumes 1 byte of the fuzzer input or returns a value if no data
* available. * available.
@ -118,10 +81,10 @@ public:
* @endcode * @endcode
*/ */
#define CONSUME1_OR_RETURN_VAL(TYPE, NAME, INPUT, VAL) \ #define CONSUME1_OR_RETURN_VAL(TYPE, NAME, INPUT, VAL) \
if (INPUT.size() < sizeof(TYPE)) { \ if (INPUT.size < sizeof(TYPE)) { \
return VAL; \ return VAL; \
} \ } \
TYPE NAME = INPUT.consume1(__func__) TYPE NAME = INPUT.consume1()
/** @brief Consumes SIZE bytes of the fuzzer input or returns if not enough data available. /** @brief Consumes SIZE bytes of the fuzzer input or returns if not enough data available.
* *
@ -135,55 +98,39 @@ public:
* @endcode * @endcode
*/ */
#define CONSUME_OR_RETURN(DECL, INPUT, SIZE) \ #define CONSUME_OR_RETURN(DECL, INPUT, SIZE) \
if (INPUT.size() < SIZE) { \ if (INPUT.size < SIZE) { \
return; \ return; \
} \ } \
DECL = INPUT.consume(__func__, SIZE) DECL = INPUT.consume(SIZE)
#define CONSUME_OR_RETURN_VAL(DECL, INPUT, SIZE, VAL) \ #define CONSUME_OR_RETURN_VAL(DECL, INPUT, SIZE, VAL) \
if (INPUT.size() < SIZE) { \ if (INPUT.size < SIZE) { \
return VAL; \ return VAL; \
} \ } \
DECL = INPUT.consume(__func__, SIZE) DECL = INPUT.consume(SIZE)
#define CONSUME_OR_ABORT(DECL, INPUT, SIZE) \ inline void fuzz_select_target(uint8_t selector, Fuzz_Data &input)
if (INPUT.size() < SIZE) { \ {
abort(); \ // The selector selected no function, so we do nothing and rely on the
} \ // fuzzer to come up with a better selector.
DECL = INPUT.consume(__func__, SIZE) }
using Fuzz_Target = void (*)(Fuzz_Data &input); template <typename Arg, typename... Args>
void fuzz_select_target(uint8_t selector, Fuzz_Data &input, Arg &&fn, Args &&...args)
template <Fuzz_Target... Args> {
struct Fuzz_Target_Selector; if (selector == sizeof...(Args)) {
return fn(input);
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 <> template <typename... Args>
struct Fuzz_Target_Selector<> { void fuzz_select_target(const uint8_t *data, std::size_t size, Args &&...args)
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}; Fuzz_Data input{data, size};
CONSUME1_OR_RETURN(const uint8_t, selector, input); CONSUME1_OR_RETURN(const uint8_t, selector, input);
return Fuzz_Target_Selector<Args...>::select(selector, input); return fuzz_select_target(selector, input, std::forward<Args>(args)...);
} }
struct Memory; struct Memory;
@ -191,18 +138,6 @@ struct Network;
struct Random; struct Random;
struct System { 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<Tox_System> sys;
std::unique_ptr<Memory> mem; std::unique_ptr<Memory> mem;
std::unique_ptr<Network> ns; std::unique_ptr<Network> ns;
@ -215,6 +150,16 @@ struct System {
// Not inline because sizeof of the above 2 structs is not known everywhere. // Not inline because sizeof of the above 2 structs is not known everywhere.
~System(); ~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 * During bootstrap, move the time forward a decent amount, because friend
* finding and bootstrapping takes significant (around 10 seconds) wall * finding and bootstrapping takes significant (around 10 seconds) wall
@ -265,8 +210,6 @@ struct Null_System : System {
* initialised with the same seed will be identical (same keys, etc.). * initialised with the same seed will be identical (same keys, etc.).
*/ */
struct Record_System : System { struct Record_System : System {
static constexpr bool DEBUG = Fuzz_Data::DEBUG;
/** @brief State shared between all tox instances. */ /** @brief State shared between all tox instances. */
struct Global { struct Global {
/** @brief Bound UDP ports and their system instance. /** @brief Bound UDP ports and their system instance.
@ -288,60 +231,13 @@ struct Record_System : System {
std::deque<std::pair<uint16_t, std::vector<uint8_t>>> recvq; std::deque<std::pair<uint16_t, std::vector<uint8_t>>> recvq;
uint16_t port = 0; //!< Sending port for this system instance. uint16_t port = 0; //!< Sending port for this system instance.
std::vector<uint8_t> recording;
Record_System(Global &global, uint64_t seed, const char *name); explicit 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. /** @brief Deposit a network packet in this instance's recvq.
*/ */
void receive(uint16_t send_port, const uint8_t *buf, size_t len); 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. /** @brief Enable debug logging.

View File

@ -17,8 +17,8 @@
* *
* Usage: * Usage:
* *
* bazel build //c-toxcore/testing/fuzzing:protodump && \ * bazel build //c-toxcore/testing/fuzzing:protodump_bin && \
* bazel-bin/c-toxcore/testing/fuzzing/protodump * bazel-bin/c-toxcore/testing/fuzzing/protodump_bin
*/ */
#include <array> #include <array>
#include <cassert> #include <cassert>
@ -165,14 +165,15 @@ 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::printf("%zu bytes: %s\n", recording.size(), filename);
std::ofstream(filename, std::ios::binary) std::ofstream(filename, std::ios::binary)
.write(reinterpret_cast<const char *>(recording.data()), recording.size()); .write(reinterpret_cast<const char *>(recording.data()), recording.size());
recording.clear();
} }
void RecordBootstrap(const char *init, const char *bootstrap) void RecordBootstrap()
{ {
Record_System::Global global; Record_System::Global global;
@ -257,17 +258,13 @@ void RecordBootstrap(const char *init, const char *bootstrap)
sys1.clock += clock_increment; sys1.clock += clock_increment;
sys2.clock += clock_increment; sys2.clock += clock_increment;
if (Fuzz_Data::DEBUG) { sys1.recording.push_back(clock_increment);
printf("tox1: rng: %d (for clock)\n", clock_increment); sys2.recording.push_back(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 while (tox_self_get_connection_status(tox1) == TOX_CONNECTION_NONE
|| tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE) { || tox_self_get_connection_status(tox2) == TOX_CONNECTION_NONE) {
if (Fuzz_Data::DEBUG) { if (DEBUG) {
std::printf("tox1: %d, tox2: %d\n", tox_self_get_connection_status(tox1), std::printf("tox1: %d, tox2: %d\n", tox_self_get_connection_status(tox1),
tox_self_get_connection_status(tox2)); tox_self_get_connection_status(tox2));
} }
@ -282,7 +279,7 @@ void RecordBootstrap(const char *init, const char *bootstrap)
while (tox_friend_get_connection_status(tox2, friend_number, nullptr) == TOX_CONNECTION_NONE while (tox_friend_get_connection_status(tox2, friend_number, nullptr) == TOX_CONNECTION_NONE
|| tox_friend_get_connection_status(tox1, 0, nullptr) == TOX_CONNECTION_NONE) { || tox_friend_get_connection_status(tox1, 0, nullptr) == TOX_CONNECTION_NONE) {
if (Fuzz_Data::DEBUG) { if (DEBUG) {
std::printf("tox1: %d, tox2: %d, tox1 -> tox2: %d, tox2 -> tox1: %d\n", 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_self_get_connection_status(tox1), tox_self_get_connection_status(tox2),
tox_friend_get_connection_status(tox1, 0, nullptr), tox_friend_get_connection_status(tox1, 0, nullptr),
@ -293,10 +290,10 @@ void RecordBootstrap(const char *init, const char *bootstrap)
std::printf("tox clients connected\n"); std::printf("tox clients connected\n");
dump(sys1.take_recording(), init); dump(sys1.recording, "tools/toktok-fuzzer/init/e2e_fuzz_test.dat");
while (done1 < MESSAGE_COUNT && done2 < MESSAGE_COUNT) { while (done1 < MESSAGE_COUNT && done2 < MESSAGE_COUNT) {
if (Fuzz_Data::DEBUG) { if (DEBUG) {
std::printf("tox1: %d, tox2: %d, tox1 -> tox2: %d, tox2 -> tox1: %d\n", 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_self_get_connection_status(tox1), tox_self_get_connection_status(tox2),
tox_friend_get_connection_status(tox1, 0, nullptr), tox_friend_get_connection_status(tox1, 0, nullptr),
@ -311,18 +308,9 @@ void RecordBootstrap(const char *init, const char *bootstrap)
tox_kill(tox2); tox_kill(tox2);
tox_kill(tox1); tox_kill(tox1);
dump(sys1.recording(), bootstrap); dump(sys1.recording, "tools/toktok-fuzzer/corpus/e2e_fuzz_test/bootstrap.dat");
} }
} }
int main(int argc, char *argv[]) int main(void) { RecordBootstrap(); }
{
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);
}

View File

@ -11,7 +11,14 @@
namespace { namespace {
constexpr bool PROTODUMP_DEBUG = Fuzz_Data::DEBUG; /**
* 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;
void setup_callbacks(Tox_Dispatch *dispatch) void setup_callbacks(Tox_Dispatch *dispatch)
{ {
@ -25,7 +32,10 @@ void setup_callbacks(Tox_Dispatch *dispatch)
}); });
tox_events_callback_conference_invite( tox_events_callback_conference_invite(
dispatch, [](Tox *tox, const Tox_Event_Conference_Invite *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Conference_Invite *event, void *user_data) {
assert(event == nullptr); 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);
}); });
tox_events_callback_conference_message( tox_events_callback_conference_message(
dispatch, [](Tox *tox, const Tox_Event_Conference_Message *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Conference_Message *event, void *user_data) {
@ -49,7 +59,9 @@ void setup_callbacks(Tox_Dispatch *dispatch)
}); });
tox_events_callback_file_recv( tox_events_callback_file_recv(
dispatch, [](Tox *tox, const Tox_Event_File_Recv *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_File_Recv *event, void *user_data) {
assert(event == nullptr); 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);
}); });
tox_events_callback_file_recv_chunk( tox_events_callback_file_recv_chunk(
dispatch, [](Tox *tox, const Tox_Event_File_Recv_Chunk *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_File_Recv_Chunk *event, void *user_data) {
@ -64,65 +76,58 @@ void setup_callbacks(Tox_Dispatch *dispatch)
// OK: friend came online. // OK: friend came online.
const uint32_t friend_number const uint32_t friend_number
= tox_event_friend_connection_status_get_friend_number(event); = tox_event_friend_connection_status_get_friend_number(event);
assert(friend_number == 0); assert(friend_number != UINT32_MAX);
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( tox_events_callback_friend_lossless_packet(
dispatch, [](Tox *tox, const Tox_Event_Friend_Lossless_Packet *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Lossless_Packet *event, void *user_data) {
assert(event == nullptr); 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);
}); });
tox_events_callback_friend_lossy_packet( tox_events_callback_friend_lossy_packet(
dispatch, [](Tox *tox, const Tox_Event_Friend_Lossy_Packet *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Lossy_Packet *event, void *user_data) {
assert(event == nullptr); 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);
}); });
tox_events_callback_friend_message( tox_events_callback_friend_message(
dispatch, [](Tox *tox, const Tox_Event_Friend_Message *event, void *user_data) { 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 uint32_t friend_number = tox_event_friend_message_get_friend_number(event);
assert(friend_number == 0); const Tox_Message_Type type = tox_event_friend_message_get_type(event);
const uint32_t message_length = tox_event_friend_message_get_message_length(event); 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); const uint8_t *message = tox_event_friend_message_get_message(event);
const uint8_t reply = message[0] + 1; tox_friend_send_message(tox, friend_number, type, message, message_length, nullptr);
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( tox_events_callback_friend_name(
dispatch, [](Tox *tox, const Tox_Event_Friend_Name *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Name *event, void *user_data) {
const uint32_t friend_number = tox_event_friend_name_get_friend_number(event); // OK: friend name received.
assert(friend_number == 0);
}); });
tox_events_callback_friend_read_receipt( tox_events_callback_friend_read_receipt(
dispatch, [](Tox *tox, const Tox_Event_Friend_Read_Receipt *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Read_Receipt *event, void *user_data) {
const uint32_t friend_number = tox_event_friend_read_receipt_get_friend_number(event); // OK: message has been received.
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( tox_events_callback_friend_request(
dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Request *event, void *user_data) {
Tox_Err_Friend_Add err; Tox_Err_Friend_Add err;
tox_friend_add_norequest(tox, tox_event_friend_request_get_public_key(event), &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( tox_events_callback_friend_status(
dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Status *event, void *user_data) {
const uint32_t friend_number = tox_event_friend_status_get_friend_number(event); // OK: friend status received.
assert(friend_number == 0);
}); });
tox_events_callback_friend_status_message( tox_events_callback_friend_status_message(
dispatch, [](Tox *tox, const Tox_Event_Friend_Status_Message *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Status_Message *event, void *user_data) {
const uint32_t friend_number = tox_event_friend_status_message_get_friend_number(event); // OK: friend status message received.
assert(friend_number == 0);
}); });
tox_events_callback_friend_typing( tox_events_callback_friend_typing(
dispatch, [](Tox *tox, const Tox_Event_Friend_Typing *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Friend_Typing *event, void *user_data) {
const uint32_t friend_number = tox_event_friend_typing_get_friend_number(event); // OK: friend may be typing.
assert(friend_number == 0);
assert(!tox_event_friend_typing_get_typing(event));
}); });
tox_events_callback_self_connection_status( tox_events_callback_self_connection_status(
dispatch, [](Tox *tox, const Tox_Event_Self_Connection_Status *event, void *user_data) { dispatch, [](Tox *tox, const Tox_Event_Self_Connection_Status *event, void *user_data) {
@ -132,15 +137,6 @@ void setup_callbacks(Tox_Dispatch *dispatch)
void TestEndToEnd(Fuzz_Data &input) 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); Fuzz_System sys(input);
Ptr<Tox_Options> opts(tox_options_new(nullptr), tox_options_free); Ptr<Tox_Options> opts(tox_options_new(nullptr), tox_options_free);
@ -152,7 +148,7 @@ void TestEndToEnd(Fuzz_Data &input)
[](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func, [](Tox *tox, Tox_Log_Level level, const char *file, uint32_t line, const char *func,
const char *message, void *user_data) { const char *message, void *user_data) {
// Log to stdout. // Log to stdout.
if (PROTODUMP_DEBUG) { if (DEBUG) {
std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line, std::printf("[tox1] %c %s:%d(%s): %s\n", tox_log_level_name(level), file, line,
func, message); func, message);
} }
@ -175,26 +171,20 @@ void TestEndToEnd(Fuzz_Data &input)
assert(dispatch != nullptr); assert(dispatch != nullptr);
setup_callbacks(dispatch); setup_callbacks(dispatch);
while (!input.empty()) { while (input.size > 0) {
Tox_Err_Events_Iterate error_iterate; Tox_Err_Events_Iterate error_iterate;
Tox_Events *events = tox_events_iterate(tox, true, &error_iterate); Tox_Events *events = tox_events_iterate(tox, true, &error_iterate);
tox_events_equal(tox_get_system(tox), events, events); // TODO(iphydf): assert? assert(tox_events_equal(tox_get_system(tox), events, events));
tox_dispatch_invoke(dispatch, events, tox, nullptr); tox_dispatch_invoke(dispatch, events, tox, nullptr);
tox_events_free(events); tox_events_free(events);
const uint8_t clock_increment = random_u08(sys.rng.get()); sys.clock += std::max(System::MIN_ITERATION_INTERVAL, 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 (PROTODUMP_REDUCE) { if (REDUCE_PROTODUMP) {
assert(tox_friend_get_connection_status(tox, 0, nullptr) != 2); assert(tox_friend_get_connection_status(tox, 0, nullptr) != 2);
} else { } else {
printf("friend: %d\n", tox_friend_get_connection_status(tox, 0, nullptr)); printf("friend: %d\n", tox_friend_get_connection_status(tox, 0, nullptr));
printf("self: %d\n", tox_self_get_connection_status(tox)); 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); tox_dispatch_free(dispatch);

View File

@ -1,14 +0,0 @@
#!/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"

View File

@ -17,7 +17,7 @@ void TestSaveDataLoading(Fuzz_Data &input)
assert(tox_options != nullptr); assert(tox_options != nullptr);
assert(error_options == TOX_ERR_OPTIONS_NEW_OK); 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); CONSUME_OR_RETURN(const uint8_t *savedata, input, savedata_size);
Null_System sys; Null_System sys;

View File

@ -5,7 +5,7 @@ COMMON_CMAKE_OPTIONS="-DCMAKE_C_COMPILER=afl-clang-lto -DCMAKE_CXX_COMPILER=afl-
# move to repo root # move to repo root
cd ../ cd ../
# build fuzz_test target UBSAN # build fuzzer target UBSAN
mkdir -p _afl_build_ubsan mkdir -p _afl_build_ubsan
cd _afl_build_ubsan cd _afl_build_ubsan
@ -14,14 +14,14 @@ export AFL_USE_UBSAN=1
# build c-toxcore using afl instrumentation # build c-toxcore using afl instrumentation
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" .. cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
# build fuzz_test target # build fuzzer target
cmake --build ./ --target bootstrap_fuzz_test cmake --build ./ --target bootstrap_fuzzer
unset AFL_USE_UBSAN unset AFL_USE_UBSAN
cd .. cd ..
# build fuzz_test target MSAN # build fuzzer target MSAN
mkdir -p _afl_build_msan mkdir -p _afl_build_msan
cd _afl_build_msan cd _afl_build_msan
@ -30,14 +30,14 @@ export AFL_USE_MSAN=1
# build c-toxcore using afl instrumentation # build c-toxcore using afl instrumentation
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" .. cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
# build fuzz_test target # build fuzzer target
cmake --build ./ --target bootstrap_fuzz_test cmake --build ./ --target bootstrap_fuzzer
unset AFL_USE_MSAN unset AFL_USE_MSAN
cd .. cd ..
# build fuzz_test target ASAN # build fuzzer target ASAN
mkdir -p _afl_build_asan mkdir -p _afl_build_asan
cd _afl_build_asan cd _afl_build_asan
@ -46,26 +46,26 @@ export AFL_USE_ASAN=1
# build c-toxcore using afl instrumentation # build c-toxcore using afl instrumentation
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" .. cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
# build fuzz_test target # build fuzzer target
cmake --build ./ --target bootstrap_fuzz_test cmake --build ./ --target bootstrap_fuzzer
unset AFL_USE_ASAN unset AFL_USE_ASAN
cd .. cd ..
# build fuzz_test target without sanitizers for afl-tmin # build fuzzer target without sanitizers for afl-tmin
mkdir -p _afl_build mkdir -p _afl_build
cd _afl_build cd _afl_build
# build c-toxcore using afl instrumentation # build c-toxcore using afl instrumentation
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" .. cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
# build fuzz_test target # build fuzzer target
cmake --build ./ --target bootstrap_fuzz_test cmake --build ./ --target bootstrap_fuzzer
cd .. cd ..
# build fuzz_test target with CmpLog # build fuzzer target with CmpLog
mkdir -p _afl_build_cmplog mkdir -p _afl_build_cmplog
cd _afl_build_cmplog cd _afl_build_cmplog
@ -74,27 +74,27 @@ export AFL_LLVM_CMPLOG=1
# build c-toxcore using afl instrumentation # build c-toxcore using afl instrumentation
cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" .. cmake -DCMAKE_BUILD_TYPE=Debug "$COMMON_CMAKE_OPTIONS" ..
# build fuzz_test target # build fuzzer target
cmake --build ./ --target bootstrap_fuzz_test cmake --build ./ --target bootstrap_fuzzer
unset AFL_LLVM_CMPLOG unset AFL_LLVM_CMPLOG
cd .. cd ..
# build fuzz_test target for code coverage # build fuzzer target for code coverage
mkdir -p _cov_build mkdir -p _cov_build
cd _cov_build cd _cov_build
# build c-toxcore using afl instrumentation # 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" .. 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 fuzz_test target # build fuzzer target
cmake --build ./ --target bootstrap_fuzz_test cmake --build ./ --target bootstrap_fuzzer
# back to repo root # back to repo root
cd ../ cd ../
# Create fuzz_test working directory # Create fuzzer working directory
mkdir -p _afl_out mkdir -p _afl_out
@ -106,21 +106,21 @@ export AFL_AUTORESUME=1
# faster startup # faster startup
export AFL_FAST_CAL=1 export AFL_FAST_CAL=1
echo "connect to the fuzz_tests using: screen -x fuzz" echo "connect to the fuzzers using: screen -x fuzz"
echo "if fuzzing doesn't start execute the following as root:" echo "if fuzzing doesn't start execute the following as root:"
echo "" echo ""
echo "echo core >/proc/sys/kernel/core_pattern" echo "echo core >/proc/sys/kernel/core_pattern"
echo "echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor" echo "echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor"
# Main fuzz_test, keeps complete corpus # Main fuzzer, keeps complete corpus
screen -dmS fuzz afl-fuzz -M fuzz0 "$AFL_ARGS" -c ./_afl_build_cmplog/bootstrap_fuzz_test ./_afl_build/bootstrap_fuzz_test screen -dmS fuzz afl-fuzz -M fuzz0 "$AFL_ARGS" -c ./_afl_build_cmplog/bootstrap_fuzzer ./_afl_build/bootstrap_fuzzer
sleep 10s sleep 10s
# Secondary fuzz_tests # Secondary fuzzers
screen -S fuzz -X screen afl-fuzz -S fuzz1 "$AFL_ARGS" -- ./_afl_build_msan/bootstrap_fuzz_test screen -S fuzz -X screen afl-fuzz -S fuzz1 "$AFL_ARGS" -- ./_afl_build_msan/bootstrap_fuzzer
sleep 1s sleep 1s
screen -S fuzz -X screen afl-fuzz -S fuzz2 "$AFL_ARGS" ./_afl_build_ubsan/bootstrap_fuzz_test screen -S fuzz -X screen afl-fuzz -S fuzz2 "$AFL_ARGS" ./_afl_build_ubsan/bootstrap_fuzzer
sleep 1s sleep 1s
screen -S fuzz -X screen afl-fuzz -S fuzz3 "$AFL_ARGS" ./_afl_build_asan/bootstrap_fuzz_test screen -S fuzz -X screen afl-fuzz -S fuzz3 "$AFL_ARGS" ./_afl_build_asan/bootstrap_fuzzer

View File

@ -1,5 +1,6 @@
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load("@rules_cc//cc:defs.bzl", "cc_test")
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test") load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test")
load("//tools:no_undefined.bzl", "cc_library")
exports_files( exports_files(
srcs = [ srcs = [
@ -11,7 +12,6 @@ exports_files(
cc_library( cc_library(
name = "test_util", name = "test_util",
testonly = True,
srcs = ["test_util.cc"], srcs = ["test_util.cc"],
hdrs = ["test_util.hh"], hdrs = ["test_util.hh"],
) )
@ -52,17 +52,6 @@ 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( cc_test(
name = "mem_test", name = "mem_test",
size = "small", size = "small",
@ -173,7 +162,6 @@ cc_library(
cc_library( cc_library(
name = "crypto_core_test_util", name = "crypto_core_test_util",
testonly = True,
srcs = ["crypto_core_test_util.cc"], srcs = ["crypto_core_test_util.cc"],
hdrs = ["crypto_core_test_util.hh"], hdrs = ["crypto_core_test_util.hh"],
deps = [ deps = [
@ -252,7 +240,6 @@ cc_test(
size = "small", size = "small",
srcs = ["mono_time_test.cc"], srcs = ["mono_time_test.cc"],
deps = [ deps = [
":mem_test_util",
":mono_time", ":mono_time",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
@ -305,7 +292,6 @@ cc_library(
cc_library( cc_library(
name = "network_test_util", name = "network_test_util",
testonly = True,
srcs = ["network_test_util.cc"], srcs = ["network_test_util.cc"],
hdrs = ["network_test_util.hh"], hdrs = ["network_test_util.hh"],
deps = [ deps = [
@ -321,7 +307,6 @@ cc_test(
srcs = ["network_test.cc"], srcs = ["network_test.cc"],
deps = [ deps = [
":network", ":network",
":network_test_util",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
@ -356,7 +341,6 @@ cc_test(
size = "small", size = "small",
srcs = ["ping_array_test.cc"], srcs = ["ping_array_test.cc"],
deps = [ deps = [
":mem_test_util",
":mono_time", ":mono_time",
":ping_array", ":ping_array",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
@ -415,7 +399,6 @@ cc_library(
cc_library( cc_library(
name = "DHT_test_util", name = "DHT_test_util",
testonly = True,
srcs = ["DHT_test_util.cc"], srcs = ["DHT_test_util.cc"],
hdrs = ["DHT_test_util.hh"], hdrs = ["DHT_test_util.hh"],
deps = [ deps = [
@ -435,7 +418,6 @@ cc_test(
":DHT", ":DHT",
":DHT_test_util", ":DHT_test_util",
":crypto_core", ":crypto_core",
":mem_test_util",
":network_test_util", ":network_test_util",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
@ -486,7 +468,7 @@ cc_fuzz_test(
name = "forwarding_fuzz_test", name = "forwarding_fuzz_test",
size = "small", size = "small",
srcs = ["forwarding_fuzz_test.cc"], srcs = ["forwarding_fuzz_test.cc"],
corpus = ["//tools/toktok-fuzzer/corpus:forwarding_fuzz_test"], #corpus = ["//tools/toktok-fuzzer/corpus:forwarding_fuzz_test"],
deps = [ deps = [
":forwarding", ":forwarding",
"//c-toxcore/testing/fuzzing:fuzz_support", "//c-toxcore/testing/fuzzing:fuzz_support",
@ -659,26 +641,12 @@ cc_test(
srcs = ["group_announce_test.cc"], srcs = ["group_announce_test.cc"],
deps = [ deps = [
":group_announce", ":group_announce",
":mem_test_util",
":mono_time", ":mono_time",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main", "@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( cc_library(
name = "group_onion_announce", name = "group_onion_announce",
srcs = ["group_onion_announce.c"], srcs = ["group_onion_announce.c"],
@ -695,6 +663,17 @@ 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( cc_library(
name = "onion_client", name = "onion_client",
srcs = ["onion_client.c"], srcs = ["onion_client.c"],
@ -780,10 +759,8 @@ cc_test(
srcs = ["group_moderation_test.cc"], srcs = ["group_moderation_test.cc"],
deps = [ deps = [
":crypto_core", ":crypto_core",
":crypto_core_test_util",
":group_moderation", ":group_moderation",
":logger", ":logger",
":mem_test_util",
":util", ":util",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
@ -793,12 +770,10 @@ cc_test(
cc_fuzz_test( cc_fuzz_test(
name = "group_moderation_fuzz_test", name = "group_moderation_fuzz_test",
size = "small", size = "small",
testonly = True,
srcs = ["group_moderation_fuzz_test.cc"], srcs = ["group_moderation_fuzz_test.cc"],
corpus = ["//tools/toktok-fuzzer/corpus:group_moderation_fuzz_test"], corpus = ["//tools/toktok-fuzzer/corpus:group_moderation_fuzz_test"],
deps = [ deps = [
":group_moderation", ":group_moderation",
":mem_test_util",
"//c-toxcore/testing/fuzzing:fuzz_support", "//c-toxcore/testing/fuzzing:fuzz_support",
], ],
) )

View File

@ -17,8 +17,8 @@ void TestHandleRequest(Fuzz_Data &input)
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
uint8_t request[MAX_CRYPTO_REQUEST_SIZE]; uint8_t request[MAX_CRYPTO_REQUEST_SIZE];
uint8_t request_id; uint8_t request_id;
handle_request(self_public_key, self_secret_key, public_key, request, &request_id, input.data(), handle_request(
input.size()); self_public_key, self_secret_key, public_key, request, &request_id, input.data, input.size);
} }
void TestUnpackNodes(Fuzz_Data &input) void TestUnpackNodes(Fuzz_Data &input)
@ -28,8 +28,8 @@ void TestUnpackNodes(Fuzz_Data &input)
const uint16_t node_count = 5; const uint16_t node_count = 5;
Node_format nodes[node_count]; Node_format nodes[node_count];
uint16_t processed_data_len; uint16_t processed_data_len;
const int packed_count = unpack_nodes( const int packed_count
nodes, node_count, &processed_data_len, input.data(), input.size(), tcp_enabled); = unpack_nodes(nodes, node_count, &processed_data_len, input.data, input.size, tcp_enabled);
if (packed_count > 0) { if (packed_count > 0) {
Logger *logger = logger_new(); Logger *logger = logger_new();
std::vector<uint8_t> packed(packed_count * PACKED_NODE_SIZE_IP6); std::vector<uint8_t> packed(packed_count * PACKED_NODE_SIZE_IP6);
@ -45,11 +45,8 @@ void TestUnpackNodes(Fuzz_Data &input)
uint16_t processed_data_len2; uint16_t processed_data_len2;
const int packed_count2 = unpack_nodes( const int packed_count2 = unpack_nodes(
nodes2, node_count, &processed_data_len2, packed.data(), packed.size(), tcp_enabled); 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(processed_data_len2 == processed_data_len);
assert(packed_count2 == packed_count); assert(packed_count2 == packed_count);
#endif
assert(memcmp(nodes, nodes2, sizeof(Node_format) * packed_count) == 0); assert(memcmp(nodes, nodes2, sizeof(Node_format) * packed_count) == 0);
} }
} }
@ -59,6 +56,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);
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<TestHandleRequest, TestUnpackNodes>(data, size); fuzz_select_target(data, size, TestHandleRequest, TestUnpackNodes);
return 0; return 0;
} }

View File

@ -11,7 +11,6 @@
#include "DHT_test_util.hh" #include "DHT_test_util.hh"
#include "crypto_core.h" #include "crypto_core.h"
#include "crypto_core_test_util.hh" #include "crypto_core_test_util.hh"
#include "mem_test_util.hh"
#include "network_test_util.hh" #include "network_test_util.hh"
namespace { namespace {
@ -327,8 +326,8 @@ TEST(Request, CreateAndParse)
TEST(AnnounceNodes, SetAndTest) TEST(AnnounceNodes, SetAndTest)
{ {
Test_Random rng; Test_Random rng;
Test_Memory mem; const Network *ns = system_network();
Test_Network ns; const Memory *mem = system_memory();
Logger *log = logger_new(); Logger *log = logger_new();
ASSERT_NE(log, nullptr); ASSERT_NE(log, nullptr);

View File

@ -437,10 +437,14 @@ 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) 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); random_bytes(rng, secret_key, CRYPTO_SECRET_KEY_SIZE);
memset(public_key, 0, CRYPTO_PUBLIC_KEY_SIZE); // Make MSAN happy memset(public_key, 0, CRYPTO_PUBLIC_KEY_SIZE); // Make MSAN happy
crypto_derive_public_key(public_key, secret_key); crypto_derive_public_key(public_key, secret_key);
return 0; 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) void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key)

View File

@ -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);
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<TestSendForwardRequest, TestForwardReply>(data, size); fuzz_select_target(data, size, TestSendForwardRequest, TestForwardReply);
return 0; return 0;
} }

View File

@ -6,7 +6,6 @@
#include <vector> #include <vector>
#include "../testing/fuzzing/fuzz_support.h" #include "../testing/fuzzing/fuzz_support.h"
#include "mem_test_util.hh"
namespace { namespace {
@ -20,7 +19,7 @@ void TestUnpackAnnouncesList(Fuzz_Data &input)
CONSUME1_OR_RETURN(const uint16_t, packed_size, input); CONSUME1_OR_RETURN(const uint16_t, packed_size, input);
Logger *logger = logger_new(); 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) { != -1) {
// Always allocate at least something to avoid passing nullptr to functions below. // Always allocate at least something to avoid passing nullptr to functions below.
std::vector<uint8_t> packed(packed_size + 1); std::vector<uint8_t> packed(packed_size + 1);
@ -39,7 +38,7 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input)
CONSUME1_OR_RETURN(const uint16_t, packed_size, input); CONSUME1_OR_RETURN(const uint16_t, packed_size, input);
Logger *logger = logger_new(); 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. // Always allocate at least something to avoid passing nullptr to functions below.
std::vector<uint8_t> packed(packed_size + 1); std::vector<uint8_t> packed(packed_size + 1);
gca_pack_public_announce(logger, packed.data(), packed_size, &public_announce); gca_pack_public_announce(logger, packed.data(), packed_size, &public_announce);
@ -49,19 +48,19 @@ void TestUnpackPublicAnnounce(Fuzz_Data &input)
void TestDoGca(Fuzz_Data &input) void TestDoGca(Fuzz_Data &input)
{ {
Test_Memory mem; const Memory *mem = system_memory();
std::unique_ptr<Logger, void (*)(Logger *)> logger(logger_new(), logger_kill); std::unique_ptr<Logger, void (*)(Logger *)> logger(logger_new(), logger_kill);
uint64_t clock = 1;
std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time( std::unique_ptr<Mono_Time, std::function<void(Mono_Time *)>> mono_time(
mono_time_new( mono_time_new(mem, nullptr, nullptr), [mem](Mono_Time *ptr) { mono_time_free(mem, ptr); });
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); 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<GC_Announces_List, void (*)(GC_Announces_List *)> gca(new_gca_list(), kill_gca); std::unique_ptr<GC_Announces_List, void (*)(GC_Announces_List *)> gca(new_gca_list(), kill_gca);
assert(gca != nullptr); assert(gca != nullptr);
while (!input.empty()) { while (input.size > 0) {
CONSUME1_OR_RETURN(const uint8_t, choice, input); CONSUME1_OR_RETURN(const uint8_t, choice, input);
switch (choice) { switch (choice) {
case 0: { case 0: {
@ -85,8 +84,7 @@ void TestDoGca(Fuzz_Data &input)
case 2: { case 2: {
// Get announces. // Get announces.
CONSUME1_OR_RETURN(const uint8_t, max_nodes, input); CONSUME1_OR_RETURN(const uint8_t, max_nodes, input);
// Always allocate at least something to avoid passing nullptr to functions below. std::vector<GC_Announce> gc_announces(max_nodes);
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 *chat_id, input, CHAT_ID_SIZE);
CONSUME_OR_RETURN(const uint8_t *except_public_key, input, ENC_PUBLIC_KEY_SIZE); CONSUME_OR_RETURN(const uint8_t *except_public_key, input, ENC_PUBLIC_KEY_SIZE);
gca_get_announces( gca_get_announces(
@ -108,6 +106,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);
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<TestUnpackAnnouncesList, TestUnpackPublicAnnounce, TestDoGca>(data, size); fuzz_select_target(data, size, TestUnpackAnnouncesList, TestUnpackPublicAnnounce, TestDoGca);
return 0; return 0;
} }

View File

@ -2,14 +2,13 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "mem_test_util.hh"
#include "mono_time.h" #include "mono_time.h"
namespace { namespace {
struct Announces : ::testing::Test { struct Announces : ::testing::Test {
protected: protected:
Test_Memory mem_; const Memory *mem_ = system_memory();
uint64_t clock_ = 1000; uint64_t clock_ = 1000;
Mono_Time *mono_time_ = nullptr; Mono_Time *mono_time_ = nullptr;
GC_Announces_List *gca_ = nullptr; GC_Announces_List *gca_ = nullptr;

View File

@ -1442,9 +1442,6 @@ 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, 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) uint8_t *packet_type, const uint8_t *packet, uint16_t length)
{ {
assert(data != nullptr);
assert(packet != nullptr);
if (length <= CRYPTO_NONCE_SIZE) { if (length <= CRYPTO_NONCE_SIZE) {
LOGGER_FATAL(log, "Invalid packet length: %u", length); LOGGER_FATAL(log, "Invalid packet length: %u", length);
return -1; return -1;
@ -4076,11 +4073,17 @@ int gc_founder_set_password(GC_Chat *chat, const uint8_t *password, uint16_t pas
return -1; return -1;
} }
uint8_t *oldpasswd = nullptr;
const uint16_t oldlen = chat->shared_state.password_length; const uint16_t oldlen = chat->shared_state.password_length;
uint8_t *oldpasswd = memdup(chat->shared_state.password, oldlen);
if (oldpasswd == nullptr && oldlen > 0) { if (oldlen > 0) {
return -4; oldpasswd = (uint8_t *)malloc(oldlen);
if (oldpasswd == nullptr) {
return -4;
}
memcpy(oldpasswd, chat->shared_state.password, oldlen);
} }
if (!set_gc_password_local(chat, password, password_length)) { if (!set_gc_password_local(chat, password, password_length)) {

View File

@ -101,12 +101,16 @@ static bool create_array_entry(const Logger *log, const Mono_Time *mono_time, GC
} }
if (length == 0) { 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 = nullptr;
array_entry->data_length = 0; array_entry->data_length = 0;
} else { } else {
if (data == nullptr) { // should never happen if (data == nullptr) {
LOGGER_FATAL(log, "Got null data with non-zero length (length: %u, type %u)", LOGGER_FATAL(log, "Got null data with non-zero length (type %u)", packet_type); // should never happen
length, packet_type);
return false; return false;
} }

View File

@ -1,16 +1,14 @@
#include "group_moderation.h" #include "group_moderation.h"
#include "../testing/fuzzing/fuzz_support.h" #include "../testing/fuzzing/fuzz_support.h"
#include "mem_test_util.hh"
namespace { namespace {
void TestModListUnpack(Fuzz_Data &input) void TestModListUnpack(Fuzz_Data &input)
{ {
CONSUME1_OR_RETURN(const uint16_t, num_mods, input); CONSUME1_OR_RETURN(const uint16_t, num_mods, input);
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem}; mod_list_unpack(&mods, input.data, input.size, num_mods);
mod_list_unpack(&mods, input.data(), input.size(), num_mods);
mod_list_cleanup(&mods); mod_list_cleanup(&mods);
} }
@ -19,7 +17,7 @@ void TestSanctionsListUnpack(Fuzz_Data &input)
Mod_Sanction sanctions[10]; Mod_Sanction sanctions[10];
Mod_Sanction_Creds creds; Mod_Sanction_Creds creds;
uint16_t processed_data_len; 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) void TestSanctionCredsUnpack(Fuzz_Data &input)
@ -34,7 +32,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);
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<TestModListUnpack, TestSanctionsListUnpack, TestSanctionCredsUnpack>( fuzz_select_target(
data, size); data, size, TestModListUnpack, TestSanctionsListUnpack, TestSanctionCredsUnpack);
return 0; return 0;
} }

View File

@ -7,9 +7,7 @@
#include <vector> #include <vector>
#include "crypto_core.h" #include "crypto_core.h"
#include "crypto_core_test_util.hh"
#include "logger.h" #include "logger.h"
#include "mem_test_util.hh"
#include "util.h" #include "util.h"
namespace { namespace {
@ -20,8 +18,7 @@ using ModerationHash = std::array<uint8_t, MOD_MODERATION_HASH_SIZE>;
TEST(ModList, PackedSizeOfEmptyModListIsZero) TEST(ModList, PackedSizeOfEmptyModListIsZero)
{ {
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
EXPECT_EQ(mod_list_packed_size(&mods), 0); EXPECT_EQ(mod_list_packed_size(&mods), 0);
uint8_t byte = 1; uint8_t byte = 1;
@ -31,16 +28,14 @@ TEST(ModList, PackedSizeOfEmptyModListIsZero)
TEST(ModList, UnpackingZeroSizeArrayIsNoop) TEST(ModList, UnpackingZeroSizeArrayIsNoop)
{ {
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
const uint8_t byte = 1; const uint8_t byte = 1;
EXPECT_EQ(mod_list_unpack(&mods, &byte, 0, 0), 0); EXPECT_EQ(mod_list_unpack(&mods, &byte, 0, 0), 0);
} }
TEST(ModList, AddRemoveMultipleMods) TEST(ModList, AddRemoveMultipleMods)
{ {
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
uint8_t sig_pk1[32] = {1}; uint8_t sig_pk1[32] = {1};
uint8_t sig_pk2[32] = {2}; uint8_t sig_pk2[32] = {2};
EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk1)); EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk1));
@ -52,8 +47,7 @@ TEST(ModList, AddRemoveMultipleMods)
TEST(ModList, PackingAndUnpackingList) TEST(ModList, PackingAndUnpackingList)
{ {
using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>; using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>;
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data())); EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data()));
std::vector<uint8_t> packed(mod_list_packed_size(&mods)); std::vector<uint8_t> packed(mod_list_packed_size(&mods));
@ -61,7 +55,7 @@ TEST(ModList, PackingAndUnpackingList)
EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data())); EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data()));
Moderation mods2{mem}; Moderation mods2{system_memory()};
EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 1), packed.size()); EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 1), packed.size());
EXPECT_TRUE(mod_list_remove_entry(&mods2, ModListEntry{}.data())); EXPECT_TRUE(mod_list_remove_entry(&mods2, ModListEntry{}.data()));
} }
@ -69,14 +63,13 @@ TEST(ModList, PackingAndUnpackingList)
TEST(ModList, UnpackingTooManyModsFails) TEST(ModList, UnpackingTooManyModsFails)
{ {
using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>; using ModListEntry = std::array<uint8_t, MOD_LIST_ENTRY_SIZE>;
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data())); EXPECT_TRUE(mod_list_add_entry(&mods, ModListEntry{}.data()));
std::vector<uint8_t> packed(mod_list_packed_size(&mods)); std::vector<uint8_t> packed(mod_list_packed_size(&mods));
mod_list_pack(&mods, packed.data()); mod_list_pack(&mods, packed.data());
Moderation mods2{mem}; Moderation mods2{system_memory()};
EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 2), -1); EXPECT_EQ(mod_list_unpack(&mods2, packed.data(), packed.size(), 2), -1);
EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data())); EXPECT_TRUE(mod_list_remove_entry(&mods, ModListEntry{}.data()));
} }
@ -85,17 +78,16 @@ TEST(ModList, UnpackingFromEmptyBufferFails)
{ {
std::vector<uint8_t> packed(1); std::vector<uint8_t> packed(1);
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
EXPECT_EQ(mod_list_unpack(&mods, packed.data(), 0, 1), -1); EXPECT_EQ(mod_list_unpack(&mods, packed.data(), 0, 1), -1);
} }
TEST(ModList, HashOfEmptyModListZeroesOutBuffer) TEST(ModList, HashOfEmptyModListZeroesOutBuffer)
{ {
Test_Memory mem; const Random *rng = system_random();
Test_Random rng; ASSERT_NE(rng, nullptr);
Moderation mods{mem}; Moderation mods{system_memory()};
// Fill with random data, check that it's zeroed. // Fill with random data, check that it's zeroed.
ModerationHash hash; ModerationHash hash;
@ -106,24 +98,21 @@ TEST(ModList, HashOfEmptyModListZeroesOutBuffer)
TEST(ModList, RemoveIndexFromEmptyModListFails) TEST(ModList, RemoveIndexFromEmptyModListFails)
{ {
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
EXPECT_FALSE(mod_list_remove_index(&mods, 0)); EXPECT_FALSE(mod_list_remove_index(&mods, 0));
EXPECT_FALSE(mod_list_remove_index(&mods, UINT16_MAX)); EXPECT_FALSE(mod_list_remove_index(&mods, UINT16_MAX));
} }
TEST(ModList, RemoveEntryFromEmptyModListFails) TEST(ModList, RemoveEntryFromEmptyModListFails)
{ {
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
uint8_t sig_pk[32] = {0}; uint8_t sig_pk[32] = {0};
EXPECT_FALSE(mod_list_remove_entry(&mods, sig_pk)); EXPECT_FALSE(mod_list_remove_entry(&mods, sig_pk));
} }
TEST(ModList, ModListRemoveIndex) TEST(ModList, ModListRemoveIndex)
{ {
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
uint8_t sig_pk[32] = {1}; uint8_t sig_pk[32] = {1};
EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk)); EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk));
EXPECT_TRUE(mod_list_remove_index(&mods, 0)); EXPECT_TRUE(mod_list_remove_index(&mods, 0));
@ -131,23 +120,20 @@ TEST(ModList, ModListRemoveIndex)
TEST(ModList, CleanupOnEmptyModsIsNoop) TEST(ModList, CleanupOnEmptyModsIsNoop)
{ {
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
mod_list_cleanup(&mods); mod_list_cleanup(&mods);
} }
TEST(ModList, EmptyModListCannotVerifyAnySigPk) TEST(ModList, EmptyModListCannotVerifyAnySigPk)
{ {
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
uint8_t sig_pk[32] = {1}; uint8_t sig_pk[32] = {1};
EXPECT_FALSE(mod_list_verify_sig_pk(&mods, sig_pk)); EXPECT_FALSE(mod_list_verify_sig_pk(&mods, sig_pk));
} }
TEST(ModList, ModListAddVerifyRemoveSigPK) TEST(ModList, ModListAddVerifyRemoveSigPK)
{ {
Test_Memory mem; Moderation mods{system_memory()};
Moderation mods{mem};
uint8_t sig_pk[32] = {1}; uint8_t sig_pk[32] = {1};
EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk)); EXPECT_TRUE(mod_list_add_entry(&mods, sig_pk));
EXPECT_TRUE(mod_list_verify_sig_pk(&mods, sig_pk)); EXPECT_TRUE(mod_list_verify_sig_pk(&mods, sig_pk));
@ -157,8 +143,7 @@ TEST(ModList, ModListAddVerifyRemoveSigPK)
TEST(ModList, ModListHashCheck) TEST(ModList, ModListHashCheck)
{ {
Test_Memory mem; Moderation mods1{system_memory()};
Moderation mods1{mem};
uint8_t sig_pk1[32] = {1}; uint8_t sig_pk1[32] = {1};
std::array<uint8_t, MOD_MODERATION_HASH_SIZE> hash1; std::array<uint8_t, MOD_MODERATION_HASH_SIZE> hash1;
@ -180,8 +165,7 @@ TEST(SanctionsList, PackingIntoUndersizedBufferFails)
TEST(SanctionsList, PackUnpackSanctionsCreds) TEST(SanctionsList, PackUnpackSanctionsCreds)
{ {
Test_Memory mem; Moderation mod{system_memory()};
Moderation mod{mem};
std::array<uint8_t, MOD_SANCTIONS_CREDS_SIZE> packed; 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(sanctions_creds_pack(&mod.sanctions_creds, packed.data()), MOD_SANCTIONS_CREDS_SIZE);
EXPECT_EQ( EXPECT_EQ(
@ -193,8 +177,7 @@ protected:
ExtPublicKey pk; ExtPublicKey pk;
ExtSecretKey sk; ExtSecretKey sk;
Logger *log = logger_new(); Logger *log = logger_new();
Test_Memory mem; Moderation mod{system_memory()};
Moderation mod{mem};
Mod_Sanction sanctions[2] = {}; Mod_Sanction sanctions[2] = {};
const uint8_t sanctioned_pk1[32] = {1}; const uint8_t sanctioned_pk1[32] = {1};

View File

@ -1,26 +0,0 @@
#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); }

View File

@ -1,39 +0,0 @@
#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

View File

@ -140,7 +140,7 @@ Mono_Time *mono_time_new(const Memory *mem, mono_time_current_time_cb *current_t
mono_time->cur_time = 0; mono_time->cur_time = 0;
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
// Maximum reproducibility. Never return time = 0. // Maximum reproducibility. Never return time = 0.
mono_time->base_time = 1000000000; mono_time->base_time = 1;
#else #else
// Never return time = 0 in case time() returns 0 (e.g. on microcontrollers // 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). // without battery-powered RTC or ones where NTP didn't initialise it yet).

View File

@ -5,13 +5,11 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include "mem_test_util.hh"
namespace { namespace {
TEST(MonoTime, UnixTimeIncreasesOverTime) TEST(MonoTime, UnixTimeIncreasesOverTime)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
ASSERT_NE(mono_time, nullptr); ASSERT_NE(mono_time, nullptr);
@ -30,7 +28,7 @@ TEST(MonoTime, UnixTimeIncreasesOverTime)
TEST(MonoTime, IsTimeout) TEST(MonoTime, IsTimeout)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
ASSERT_NE(mono_time, nullptr); ASSERT_NE(mono_time, nullptr);
@ -48,7 +46,7 @@ TEST(MonoTime, IsTimeout)
TEST(MonoTime, IsTimeoutReal) TEST(MonoTime, IsTimeoutReal)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
ASSERT_NE(mono_time, nullptr); ASSERT_NE(mono_time, nullptr);
@ -69,7 +67,7 @@ TEST(MonoTime, IsTimeoutReal)
TEST(MonoTime, CustomTime) TEST(MonoTime, CustomTime)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr); Mono_Time *mono_time = mono_time_new(mem, nullptr, nullptr);
ASSERT_NE(mono_time, nullptr); ASSERT_NE(mono_time, nullptr);

View File

@ -2,17 +2,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "network_test_util.hh"
namespace { namespace {
TEST(TestUtil, ProducesNonNullNetwork)
{
Test_Network net;
const Network *ns = net;
EXPECT_NE(ns, nullptr);
}
TEST(IpNtoa, DoesntWriteOutOfBounds) TEST(IpNtoa, DoesntWriteOutOfBounds)
{ {
Ip_Ntoa ip_str; Ip_Ntoa ip_str;

View File

@ -2,81 +2,6 @@
#include <iomanip> #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 increasing_ip_port::operator()()
{ {
IP_Port ip_port; IP_Port ip_port;

View File

@ -7,60 +7,6 @@
#include "network.h" #include "network.h"
#include "test_util.hh" #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 <> template <>
struct Deleter<Networking_Core> : Function_Deleter<Networking_Core, kill_networking> { }; struct Deleter<Networking_Core> : Function_Deleter<Networking_Core, kill_networking> { };

View File

@ -4,7 +4,6 @@
#include <memory> #include <memory>
#include "mem_test_util.hh"
#include "mono_time.h" #include "mono_time.h"
namespace { namespace {
@ -16,7 +15,7 @@ struct Ping_Array_Deleter {
using Ping_Array_Ptr = std::unique_ptr<Ping_Array, Ping_Array_Deleter>; using Ping_Array_Ptr = std::unique_ptr<Ping_Array, Ping_Array_Deleter>;
struct Mono_Time_Deleter { struct Mono_Time_Deleter {
Mono_Time_Deleter(const Test_Memory &mem) Mono_Time_Deleter(const Memory *mem)
: mem_(mem) : mem_(mem)
{ {
} }
@ -30,21 +29,21 @@ using Mono_Time_Ptr = std::unique_ptr<Mono_Time, Mono_Time_Deleter>;
TEST(PingArray, MinimumTimeoutIsOne) TEST(PingArray, MinimumTimeoutIsOne)
{ {
Test_Memory mem; const Memory *mem = system_memory();
EXPECT_EQ(ping_array_new(mem, 1, 0), nullptr); EXPECT_EQ(ping_array_new(mem, 1, 0), nullptr);
EXPECT_NE(Ping_Array_Ptr(ping_array_new(mem, 1, 1)), nullptr); EXPECT_NE(Ping_Array_Ptr(ping_array_new(mem, 1, 1)), nullptr);
} }
TEST(PingArray, MinimumArraySizeIsOne) TEST(PingArray, MinimumArraySizeIsOne)
{ {
Test_Memory mem; const Memory *mem = system_memory();
EXPECT_EQ(ping_array_new(mem, 0, 1), nullptr); EXPECT_EQ(ping_array_new(mem, 0, 1), nullptr);
EXPECT_NE(Ping_Array_Ptr(ping_array_new(mem, 1, 1)), nullptr); EXPECT_NE(Ping_Array_Ptr(ping_array_new(mem, 1, 1)), nullptr);
} }
TEST(PingArray, ArraySizeMustBePowerOfTwo) TEST(PingArray, ArraySizeMustBePowerOfTwo)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Ping_Array_Ptr arr; Ping_Array_Ptr arr;
arr.reset(ping_array_new(mem, 2, 1)); arr.reset(ping_array_new(mem, 2, 1));
@ -60,7 +59,7 @@ TEST(PingArray, ArraySizeMustBePowerOfTwo)
TEST(PingArray, StoredDataCanBeRetrieved) TEST(PingArray, StoredDataCanBeRetrieved)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1)); Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem); Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
@ -79,7 +78,7 @@ TEST(PingArray, StoredDataCanBeRetrieved)
TEST(PingArray, RetrievingDataWithTooSmallOutputBufferHasNoEffect) TEST(PingArray, RetrievingDataWithTooSmallOutputBufferHasNoEffect)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1)); Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem); Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
@ -102,7 +101,7 @@ TEST(PingArray, RetrievingDataWithTooSmallOutputBufferHasNoEffect)
TEST(PingArray, ZeroLengthDataCanBeAdded) TEST(PingArray, ZeroLengthDataCanBeAdded)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1)); Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem); Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
@ -119,7 +118,7 @@ TEST(PingArray, ZeroLengthDataCanBeAdded)
TEST(PingArray, PingId0IsInvalid) TEST(PingArray, PingId0IsInvalid)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1)); Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem); Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
@ -132,7 +131,7 @@ TEST(PingArray, PingId0IsInvalid)
// Protection against replay attacks. // Protection against replay attacks.
TEST(PingArray, DataCanOnlyBeRetrievedOnce) TEST(PingArray, DataCanOnlyBeRetrievedOnce)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1)); Ping_Array_Ptr const arr(ping_array_new(mem, 2, 1));
Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem); Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);
@ -150,7 +149,7 @@ TEST(PingArray, DataCanOnlyBeRetrievedOnce)
TEST(PingArray, PingIdMustMatchOnCheck) TEST(PingArray, PingIdMustMatchOnCheck)
{ {
Test_Memory mem; const Memory *mem = system_memory();
Ping_Array_Ptr const arr(ping_array_new(mem, 1, 1)); Ping_Array_Ptr const arr(ping_array_new(mem, 1, 1));
Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem); Mono_Time_Ptr const mono_time(mono_time_new(mem, nullptr, nullptr), mem);

View File

@ -3,10 +3,7 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstdio>
#include <cstdlib>
#include <memory> #include <memory>
#include <type_traits>
#include <vector> #include <vector>
template <typename T, void (*Delete)(T *)> template <typename T, void (*Delete)(T *)>
@ -44,7 +41,7 @@ std::array<T, N> to_array(T const (&arr)[N])
template <std::size_t N, typename T, typename... Args> template <std::size_t N, typename T, typename... Args>
auto array_of(T &&make, Args... args) auto array_of(T &&make, Args... args)
{ {
std::array<std::invoke_result_t<T, Args...>, N> arr; std::array<typename std::result_of<T(Args...)>::type, N> arr;
for (auto &elem : arr) { for (auto &elem : arr) {
elem = make(args...); elem = make(args...);
} }
@ -54,7 +51,7 @@ auto array_of(T &&make, Args... args)
template <typename T, typename... Args> template <typename T, typename... Args>
auto vector_of(std::size_t n, T &&make, Args... args) auto vector_of(std::size_t n, T &&make, Args... args)
{ {
std::vector<std::invoke_result_t<T, Args...>> vec; std::vector<typename std::result_of<T(Args...)>::type> vec;
for (std::size_t i = 0; i < n; ++i) { for (std::size_t i = 0; i < n; ++i) {
vec.push_back(make(args...)); vec.push_back(make(args...));
} }
@ -68,16 +65,4 @@ Container sorted(Container arr, Less less)
return arr; 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 #endif // C_TOXCORE_TOXCORE_TEST_UTIL_H

View File

@ -20,7 +20,7 @@ void TestUnpack(Fuzz_Data data)
// events_size bytes: events data (max 64K) // events_size bytes: events data (max 64K)
CONSUME_OR_RETURN(const uint8_t *events_data, data, events_size); CONSUME_OR_RETURN(const uint8_t *events_data, data, events_size);
if (data.empty()) { if (data.size == 0) {
// If there's no more input, no malloc failure paths can possibly be // If there's no more input, no malloc failure paths can possibly be
// tested, so we ignore this input. // tested, so we ignore this input.
return; return;

View File

@ -13,7 +13,6 @@
#include "util.h" #include "util.h"
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "ccompat.h" #include "ccompat.h"
@ -81,21 +80,6 @@ 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; 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) int16_t max_s16(int16_t a, int16_t b)
{ {
return a > b ? a : b; return a > b ? a : b;

View File

@ -41,13 +41,6 @@ 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); 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 // Safe min/max functions with specific types. This forces the conversion to the
// desired type before the comparison expression, giving the choice of // desired type before the comparison expression, giving the choice of
// conversion to the caller. Use these instead of inline comparisons or MIN/MAX // conversion to the caller. Use these instead of inline comparisons or MIN/MAX

View File

@ -55,19 +55,12 @@
libsodium libsodium
] ++ self.packages.${system}.default.dlopenBuildInputs; ] ++ self.packages.${system}.default.dlopenBuildInputs;
cmakeFlags = [
"TOMATO_ASAN=1"
"CMAKE_BUILD_TYPE=RelWithDebInfo"
];
# TODO: replace with install command # TODO: replace with install command
installPhase = '' installPhase = ''
mkdir -p $out/bin mkdir -p $out/bin
mv bin/tomato $out/bin mv bin/tomato $out/bin
''; '';
dontStrip = true;
# copied from nixpkgs's SDL2 default.nix # copied from nixpkgs's SDL2 default.nix
# SDL is weird in that instead of just dynamically linking with # SDL is weird in that instead of just dynamically linking with
# libraries when you `--enable-*` (or when `configure` finds) them # libraries when you `--enable-*` (or when `configure` finds) them

View File

@ -520,7 +520,6 @@ void ChatGui4::render(float time_delta) {
//} else if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { //} else if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
} else if (ImGui::BeginPopupContextItem(nullptr, ImGuiMouseButton_Right)) { } else if (ImGui::BeginPopupContextItem(nullptr, ImGuiMouseButton_Right)) {
const static std::vector<const char*> image_mime_types { const static std::vector<const char*> image_mime_types {
// add apng?
"image/png", "image/png",
"image/webp", "image/webp",
"image/gif", "image/gif",