From 27c27b7c8cde5ef4bdaade94aad27af9120812de Mon Sep 17 00:00:00 2001 From: iphydf Date: Sun, 10 Apr 2022 18:48:09 +0000 Subject: [PATCH] refactor: Avoid `static_cast` in `Fuzz_System` functions. Declutters the fuzz system code a bit, hiding the cast behind a `!` operator. --- testing/fuzzing/BUILD.bazel | 5 ++- testing/fuzzing/CMakeLists.txt | 2 +- testing/fuzzing/func_conversion.h | 69 +++++++++++++++++++++++++++++++ testing/fuzzing/fuzz_support.cc | 34 +++++++-------- 4 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 testing/fuzzing/func_conversion.h diff --git a/testing/fuzzing/BUILD.bazel b/testing/fuzzing/BUILD.bazel index 1135a72c..944c7035 100644 --- a/testing/fuzzing/BUILD.bazel +++ b/testing/fuzzing/BUILD.bazel @@ -5,7 +5,10 @@ package(features = ["layering_check"]) cc_library( name = "fuzz_support", - srcs = ["fuzz_support.cc"], + srcs = [ + "func_conversion.h", + "fuzz_support.cc", + ], hdrs = ["fuzz_support.h"], visibility = ["//c-toxcore:__subpackages__"], deps = [ diff --git a/testing/fuzzing/CMakeLists.txt b/testing/fuzzing/CMakeLists.txt index 5c00c764..a000ccb0 100644 --- a/testing/fuzzing/CMakeLists.txt +++ b/testing/fuzzing/CMakeLists.txt @@ -2,7 +2,7 @@ target_compile_definitions(toxcore_static PUBLIC "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION") # Override network and random functions -add_library(fuzz_support fuzz_support.cc fuzz_support.h) +add_library(fuzz_support func_conversion.h fuzz_support.cc fuzz_support.h) set(LIBFUZZER_LINKER_FLAGS) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") diff --git a/testing/fuzzing/func_conversion.h b/testing/fuzzing/func_conversion.h new file mode 100644 index 00000000..8ab9103c --- /dev/null +++ b/testing/fuzzing/func_conversion.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2022 The TokTok team. + */ + +#ifndef C_TOXCORE_TESTING_FUZZING_FUNC_CONVERSION_H +#define C_TOXCORE_TESTING_FUZZING_FUNC_CONVERSION_H + +namespace detail { + +template +struct func_conversion { +private: + template + using func_pointer = R (*)(Args...); + + template + struct static_caster { + From obj; + + template + operator To() const + { + return static_cast(obj); + } + }; + +public: + template + constexpr operator func_pointer() + { + return [](Arg obj, auto... args) { return f(static_caster{obj}, args...); }; + } +}; + +template +struct make_funptr; + +template +struct make_funptr { + using type = R (*)(Args...); +}; + +/** @brief Turn a memfunptr type into a plain funptr type. + * + * Not needed in C++20, because we can pass the lambda itself as template + * argument, but in C++17, we need to do an early conversion. + */ +template +using make_funptr_t = typename make_funptr::type; + +} + +/** @brief Turn a C++ lambda into a C function pointer with `void*` param. + * + * Takes a lambda function with any pointer type as first parameter and turns it + * into a C function pointer with `void*` as the first parameter. Internally, it + * `static_cast`s that `void*` to the lambda's parameter type, avoiding a bunch + * of casts inside the lambdas. + * + * This works on any type `T` that can be `static_cast` to `U`, not just `void*` + * to `U*`, but the common case for C callbacks is `void*`. + */ +template +static constexpr auto operator!(F f) +{ + return detail::func_conversion, f>{}; +} + +#endif // C_TOXCORE_TESTING_FUZZING_FUNC_CONVERSION_H diff --git a/testing/fuzzing/fuzz_support.cc b/testing/fuzzing/fuzz_support.cc index e5159feb..b3492135 100644 --- a/testing/fuzzing/fuzz_support.cc +++ b/testing/fuzzing/fuzz_support.cc @@ -14,6 +14,7 @@ #include "../../toxcore/crypto_core.h" #include "../../toxcore/network.h" #include "../../toxcore/tox_private.h" +#include "func_conversion.h" // TODO(iphydf): Put this somewhere shared. struct Network_Addr { @@ -40,7 +41,7 @@ static int recv_common(Fuzz_Data &input, void *buf, size_t buf_len) return res; } -static const Network_Funcs fuzz_network_funcs = { +static constexpr Network_Funcs fuzz_network_funcs = { /* .close = */ [](void *obj, int sock) { return 0; }, /* .accept = */ [](void *obj, int sock) { return 2; }, /* .bind = */ [](void *obj, int sock, const Network_Addr *addr) { return 0; }, @@ -52,12 +53,12 @@ static const Network_Funcs fuzz_network_funcs = { return 0; }, /* .recv = */ - [](void *obj, int sock, uint8_t *buf, size_t len) { + ![](Fuzz_System *self, int sock, uint8_t *buf, size_t len) { // Receive data from the fuzzer. - return recv_common(static_cast(obj)->data, buf, len); + return recv_common(self->data, buf, len); }, /* .recvfrom = */ - [](void *obj, int sock, uint8_t *buf, size_t len, Network_Addr *addr) { + ![](Fuzz_System *self, int sock, uint8_t *buf, size_t len, Network_Addr *addr) { addr->addr = sockaddr_storage{}; // Dummy Addr addr->addr.ss_family = AF_INET; @@ -68,7 +69,7 @@ static const Network_Funcs fuzz_network_funcs = { addr_in->sin_addr.s_addr = INADDR_LOOPBACK + 1; addr->size = sizeof(struct sockaddr); - return recv_common(static_cast(obj)->data, buf, len); + return recv_common(self->data, buf, len); }, /* .send = */ [](void *obj, int sock, const uint8_t *buf, size_t len) { @@ -93,24 +94,22 @@ static const Network_Funcs fuzz_network_funcs = { }, }; -static const Random_Funcs fuzz_random_funcs = { +static constexpr Random_Funcs fuzz_random_funcs = { /* .random_bytes = */ - [](void *obj, uint8_t *bytes, size_t length) { - Fuzz_System *sys = static_cast(obj); + ![](Fuzz_System *self, uint8_t *bytes, size_t length) { // Amount of data is limited - const size_t available = sys->data.size; - const size_t bytes_read = std::min(length, available); + const size_t bytes_read = std::min(length, self->data.size); // Initialize everything to make MSAN and others happy std::memset(bytes, 0, length); - std::memcpy(bytes, sys->data.data, bytes_read); - sys->data.data += bytes_read; - sys->data.size -= bytes_read; + std::memcpy(bytes, self->data.data, bytes_read); + self->data.data += bytes_read; + self->data.size -= bytes_read; }, /* .random_uniform = */ - [](void *obj, uint32_t upper_bound) { - Fuzz_System *sys = static_cast(obj); + ![](Fuzz_System *self, uint32_t upper_bound) { uint32_t randnum; - sys->rng->funcs->random_bytes(sys, reinterpret_cast(&randnum), sizeof(randnum)); + self->rng->funcs->random_bytes( + self, reinterpret_cast(&randnum), sizeof(randnum)); return randnum % upper_bound; }, }; @@ -122,8 +121,7 @@ Fuzz_System::Fuzz_System(Fuzz_Data &input) , ns(std::make_unique(Network{&fuzz_network_funcs, this})) , rng(std::make_unique(Random{&fuzz_random_funcs, this})) { - sys->mono_time_callback - = [](void *user_data) { return static_cast(user_data)->clock; }; + sys->mono_time_callback = ![](Fuzz_System *self) { return self->clock; }; sys->mono_time_user_data = this; sys->ns = ns.get(); sys->rng = rng.get();