Squashed 'external/toxcore/c-toxcore/' changes from 6d634674a9..73d9b845a3

73d9b845a3 cleanup: Remove old type-ordered event getters.
b0840cc02d feat: add ngc events
7df9a51349 refactor: Make event dispatch ordered by receive time.
bcb6592af5 test: Add C++ classes wrapping system interfaces.
4cea4f9ca4 fix: Make all the fuzzers work again, and add a test for protodump.
c4e209ea1d refactor: Factor out malloc+memcpy into memdup.
87bcc4322d fix: Remove fatal error for non-erroneous case
REVERT: 6d634674a9 cleanup: Remove old type-ordered event getters.
REVERT: d1d48d1dfc feat: add ngc events
REVERT: 994ffecc6b refactor: Make event dispatch ordered by receive time.

git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: 73d9b845a310c3f56d2d6d77ed56b93d84256d6e
This commit is contained in:
2024-01-14 21:51:01 +01:00
parent 8eb4892b49
commit b1fe064484
39 changed files with 775 additions and 307 deletions

View File

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

View File

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

View File

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

View File

@ -437,14 +437,10 @@ void new_symmetric_key(const Random *rng, uint8_t *key)
int32_t crypto_new_keypair(const Random *rng, uint8_t *public_key, uint8_t *secret_key)
{
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
random_bytes(rng, secret_key, CRYPTO_SECRET_KEY_SIZE);
memset(public_key, 0, CRYPTO_PUBLIC_KEY_SIZE); // Make MSAN happy
crypto_derive_public_key(public_key, secret_key);
return 0;
#else
return crypto_box_keypair(public_key, secret_key);
#endif
}
void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key)

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

View File

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

View File

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

View File

@ -1442,6 +1442,9 @@ non_null(1, 2, 3, 5, 6) nullable(4)
static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, uint8_t *data, uint64_t *message_id,
uint8_t *packet_type, const uint8_t *packet, uint16_t length)
{
assert(data != nullptr);
assert(packet != nullptr);
if (length <= CRYPTO_NONCE_SIZE) {
LOGGER_FATAL(log, "Invalid packet length: %u", length);
return -1;
@ -4073,17 +4076,11 @@ int gc_founder_set_password(GC_Chat *chat, const uint8_t *password, uint16_t pas
return -1;
}
uint8_t *oldpasswd = nullptr;
const uint16_t oldlen = chat->shared_state.password_length;
uint8_t *oldpasswd = memdup(chat->shared_state.password, oldlen);
if (oldlen > 0) {
oldpasswd = (uint8_t *)malloc(oldlen);
if (oldpasswd == nullptr) {
return -4;
}
memcpy(oldpasswd, chat->shared_state.password, oldlen);
if (oldpasswd == nullptr && oldlen > 0) {
return -4;
}
if (!set_gc_password_local(chat, password, password_length)) {

View File

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

View File

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

View File

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

26
toxcore/mem_test_util.cc Normal file
View File

@ -0,0 +1,26 @@
#include "mem_test_util.hh"
#include <cstdlib>
Memory_Funcs const Memory_Class::vtable = {
Method<mem_malloc_cb, Memory_Class>::invoke<&Memory_Class::malloc>,
Method<mem_calloc_cb, Memory_Class>::invoke<&Memory_Class::calloc>,
Method<mem_realloc_cb, Memory_Class>::invoke<&Memory_Class::realloc>,
Method<mem_free_cb, Memory_Class>::invoke<&Memory_Class::free>,
};
Memory_Class::~Memory_Class() = default;
void *Test_Memory::malloc(void *obj, uint32_t size) { return mem->funcs->malloc(mem->obj, size); }
void *Test_Memory::calloc(void *obj, uint32_t nmemb, uint32_t size)
{
return mem->funcs->calloc(mem->obj, nmemb, size);
}
void *Test_Memory::realloc(void *obj, void *ptr, uint32_t size)
{
return mem->funcs->realloc(mem->obj, ptr, size);
}
void Test_Memory::free(void *obj, void *ptr) { return mem->funcs->free(mem->obj, ptr); }

39
toxcore/mem_test_util.hh Normal file
View File

@ -0,0 +1,39 @@
#ifndef C_TOXCORE_TOXCORE_MEM_TEST_UTIL_H
#define C_TOXCORE_TOXCORE_MEM_TEST_UTIL_H
#include "mem.h"
#include "test_util.hh"
struct Memory_Class {
static Memory_Funcs const vtable;
Memory const self;
operator Memory const *() const { return &self; }
Memory_Class(Memory_Class const &) = default;
Memory_Class()
: self{&vtable, this}
{
}
virtual ~Memory_Class();
virtual mem_malloc_cb malloc = 0;
virtual mem_calloc_cb calloc = 0;
virtual mem_realloc_cb realloc = 0;
virtual mem_free_cb free = 0;
};
/**
* Base test Memory class that just forwards to system_memory. Can be
* subclassed to override individual (or all) functions.
*/
class Test_Memory : public Memory_Class {
const Memory *mem = REQUIRE_NOT_NULL(system_memory());
void *malloc(void *obj, uint32_t size) override;
void *calloc(void *obj, uint32_t nmemb, uint32_t size) override;
void *realloc(void *obj, void *ptr, uint32_t size) override;
void free(void *obj, void *ptr) override;
};
#endif // C_TOXCORE_TOXCORE_MEM_TEST_UTIL_H

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;
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
// Maximum reproducibility. Never return time = 0.
mono_time->base_time = 1;
mono_time->base_time = 1000000000;
#else
// Never return time = 0 in case time() returns 0 (e.g. on microcontrollers
// without battery-powered RTC or ones where NTP didn't initialise it yet).

View File

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

View File

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

View File

@ -2,6 +2,81 @@
#include <iomanip>
Network_Funcs const Network_Class::vtable = {
Method<net_close_cb, Network_Class>::invoke<&Network_Class::close>,
Method<net_accept_cb, Network_Class>::invoke<&Network_Class::accept>,
Method<net_bind_cb, Network_Class>::invoke<&Network_Class::bind>,
Method<net_listen_cb, Network_Class>::invoke<&Network_Class::listen>,
Method<net_recvbuf_cb, Network_Class>::invoke<&Network_Class::recvbuf>,
Method<net_recv_cb, Network_Class>::invoke<&Network_Class::recv>,
Method<net_recvfrom_cb, Network_Class>::invoke<&Network_Class::recvfrom>,
Method<net_send_cb, Network_Class>::invoke<&Network_Class::send>,
Method<net_sendto_cb, Network_Class>::invoke<&Network_Class::sendto>,
Method<net_socket_cb, Network_Class>::invoke<&Network_Class::socket>,
Method<net_socket_nonblock_cb, Network_Class>::invoke<&Network_Class::socket_nonblock>,
Method<net_getsockopt_cb, Network_Class>::invoke<&Network_Class::getsockopt>,
Method<net_setsockopt_cb, Network_Class>::invoke<&Network_Class::setsockopt>,
Method<net_getaddrinfo_cb, Network_Class>::invoke<&Network_Class::getaddrinfo>,
Method<net_freeaddrinfo_cb, Network_Class>::invoke<&Network_Class::freeaddrinfo>,
};
int Test_Network::close(void *obj, int sock) { return net->funcs->close(net->obj, sock); }
int Test_Network::accept(void *obj, int sock) { return net->funcs->accept(net->obj, sock); }
int Test_Network::bind(void *obj, int sock, const Network_Addr *addr)
{
return net->funcs->bind(net->obj, sock, addr);
}
int Test_Network::listen(void *obj, int sock, int backlog)
{
return net->funcs->listen(net->obj, sock, backlog);
}
int Test_Network::recvbuf(void *obj, int sock) { return net->funcs->recvbuf(net->obj, sock); }
int Test_Network::recv(void *obj, int sock, uint8_t *buf, size_t len)
{
return net->funcs->recv(net->obj, sock, buf, len);
}
int Test_Network::recvfrom(void *obj, int sock, uint8_t *buf, size_t len, Network_Addr *addr)
{
return net->funcs->recvfrom(net->obj, sock, buf, len, addr);
}
int Test_Network::send(void *obj, int sock, const uint8_t *buf, size_t len)
{
return net->funcs->send(net->obj, sock, buf, len);
}
int Test_Network::sendto(
void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr)
{
return net->funcs->sendto(net->obj, sock, buf, len, addr);
}
int Test_Network::socket(void *obj, int domain, int type, int proto)
{
return net->funcs->socket(net->obj, domain, type, proto);
}
int Test_Network::socket_nonblock(void *obj, int sock, bool nonblock)
{
return net->funcs->socket_nonblock(net->obj, sock, nonblock);
}
int Test_Network::getsockopt(
void *obj, int sock, int level, int optname, void *optval, size_t *optlen)
{
return net->funcs->getsockopt(net->obj, sock, level, optname, optval, optlen);
}
int Test_Network::setsockopt(
void *obj, int sock, int level, int optname, const void *optval, size_t optlen)
{
return net->funcs->setsockopt(net->obj, sock, level, optname, optval, optlen);
}
int Test_Network::getaddrinfo(void *obj, int family, Network_Addr **addrs)
{
return net->funcs->getaddrinfo(net->obj, family, addrs);
}
int Test_Network::freeaddrinfo(void *obj, Network_Addr *addrs)
{
return net->funcs->freeaddrinfo(net->obj, addrs);
}
Network_Class::~Network_Class() = default;
IP_Port increasing_ip_port::operator()()
{
IP_Port ip_port;

View File

@ -7,6 +7,60 @@
#include "network.h"
#include "test_util.hh"
struct Network_Class {
static Network_Funcs const vtable;
Network const self;
operator Network const *() const { return &self; }
Network_Class(Network_Class const &) = default;
Network_Class()
: self{&vtable, this}
{
}
virtual ~Network_Class();
virtual net_close_cb close = 0;
virtual net_accept_cb accept = 0;
virtual net_bind_cb bind = 0;
virtual net_listen_cb listen = 0;
virtual net_recvbuf_cb recvbuf = 0;
virtual net_recv_cb recv = 0;
virtual net_recvfrom_cb recvfrom = 0;
virtual net_send_cb send = 0;
virtual net_sendto_cb sendto = 0;
virtual net_socket_cb socket = 0;
virtual net_socket_nonblock_cb socket_nonblock = 0;
virtual net_getsockopt_cb getsockopt = 0;
virtual net_setsockopt_cb setsockopt = 0;
virtual net_getaddrinfo_cb getaddrinfo = 0;
virtual net_freeaddrinfo_cb freeaddrinfo = 0;
};
/**
* Base test Network class that just forwards to system_network. Can be
* subclassed to override individual (or all) functions.
*/
class Test_Network : public Network_Class {
const Network *net = REQUIRE_NOT_NULL(system_network());
int close(void *obj, int sock) override;
int accept(void *obj, int sock) override;
int bind(void *obj, int sock, const Network_Addr *addr) override;
int listen(void *obj, int sock, int backlog) override;
int recvbuf(void *obj, int sock) override;
int recv(void *obj, int sock, uint8_t *buf, size_t len) override;
int recvfrom(void *obj, int sock, uint8_t *buf, size_t len, Network_Addr *addr) override;
int send(void *obj, int sock, const uint8_t *buf, size_t len) override;
int sendto(void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) override;
int socket(void *obj, int domain, int type, int proto) override;
int socket_nonblock(void *obj, int sock, bool nonblock) override;
int getsockopt(void *obj, int sock, int level, int optname, void *optval, size_t *optlen) override;
int setsockopt(void *obj, int sock, int level, int optname, const void *optval, size_t optlen) override;
int getaddrinfo(void *obj, int family, Network_Addr **addrs) override;
int freeaddrinfo(void *obj, Network_Addr *addrs) override;
};
template <>
struct Deleter<Networking_Core> : Function_Deleter<Networking_Core, kill_networking> { };

View File

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

View File

@ -3,7 +3,10 @@
#include <algorithm>
#include <array>
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <type_traits>
#include <vector>
template <typename T, void (*Delete)(T *)>
@ -41,7 +44,7 @@ std::array<T, N> to_array(T const (&arr)[N])
template <std::size_t N, typename T, typename... Args>
auto array_of(T &&make, Args... args)
{
std::array<typename std::result_of<T(Args...)>::type, N> arr;
std::array<std::invoke_result_t<T, Args...>, N> arr;
for (auto &elem : arr) {
elem = make(args...);
}
@ -51,7 +54,7 @@ auto array_of(T &&make, Args... args)
template <typename T, typename... Args>
auto vector_of(std::size_t n, T &&make, Args... args)
{
std::vector<typename std::result_of<T(Args...)>::type> vec;
std::vector<std::invoke_result_t<T, Args...>> vec;
for (std::size_t i = 0; i < n; ++i) {
vec.push_back(make(args...));
}
@ -65,4 +68,16 @@ Container sorted(Container arr, Less less)
return arr;
}
template <typename T>
T *require_not_null(const char *file, int line, T *ptr)
{
if (ptr == nullptr) {
std::fprintf(stderr, "unexpected null pointer at %s:%d\n", file, line);
std::exit(7);
}
return ptr;
}
#define REQUIRE_NOT_NULL(ptr) require_not_null(__FILE__, __LINE__, ptr)
#endif // C_TOXCORE_TOXCORE_TEST_UTIL_H

View File

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

View File

@ -13,6 +13,7 @@
#include "util.h"
#include <stdlib.h>
#include <string.h>
#include "ccompat.h"
@ -80,6 +81,21 @@ bool memeq(const uint8_t *a, size_t a_size, const uint8_t *b, size_t b_size)
return a_size == b_size && memcmp(a, b, a_size) == 0;
}
uint8_t *memdup(const uint8_t *data, size_t data_size)
{
if (data == nullptr || data_size == 0) {
return nullptr;
}
uint8_t *copy = (uint8_t *)malloc(data_size);
if (copy != nullptr) {
memcpy(copy, data, data_size);
}
return copy;
}
int16_t max_s16(int16_t a, int16_t b)
{
return a > b ? a : b;

View File

@ -41,6 +41,13 @@ non_null() int create_recursive_mutex(pthread_mutex_t *mutex);
*/
non_null() bool memeq(const uint8_t *a, size_t a_size, const uint8_t *b, size_t b_size);
/**
* @brief Copies a byte array of a given size into a newly allocated one.
*
* @return nullptr on allocation failure or if the input data was nullptr or data_size was 0.
*/
nullable(1) uint8_t *memdup(const uint8_t *data, size_t data_size);
// Safe min/max functions with specific types. This forces the conversion to the
// desired type before the comparison expression, giving the choice of
// conversion to the caller. Use these instead of inline comparisons or MIN/MAX