refactor: Avoid static_cast in Fuzz_System functions.

Declutters the fuzz system code a bit, hiding the cast behind a `!`
operator.
This commit is contained in:
iphydf 2022-04-10 18:48:09 +00:00
parent 616bd63021
commit 27c27b7c8c
No known key found for this signature in database
GPG Key ID: 3855DBA2D74403C9
4 changed files with 90 additions and 20 deletions

View File

@ -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 = [

View File

@ -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")

View File

@ -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 <typename F, F f>
struct func_conversion {
private:
template <typename R, typename... Args>
using func_pointer = R (*)(Args...);
template <typename From>
struct static_caster {
From obj;
template <typename To>
operator To() const
{
return static_cast<To>(obj);
}
};
public:
template <typename R, typename Arg, typename... Args>
constexpr operator func_pointer<R, Arg, Args...>()
{
return [](Arg obj, auto... args) { return f(static_caster<Arg>{obj}, args...); };
}
};
template <typename F>
struct make_funptr;
template <typename T, typename R, typename... Args>
struct make_funptr<R (T::*)(Args...) const> {
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 <typename F>
using make_funptr_t = typename make_funptr<F>::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 <typename F>
static constexpr auto operator!(F f)
{
return detail::func_conversion<detail::make_funptr_t<decltype(&F::operator())>, f>{};
}
#endif // C_TOXCORE_TESTING_FUZZING_FUNC_CONVERSION_H

View File

@ -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<Fuzz_System *>(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<Fuzz_System *>(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<Fuzz_System *>(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<Fuzz_System *>(obj);
![](Fuzz_System *self, uint32_t upper_bound) {
uint32_t randnum;
sys->rng->funcs->random_bytes(sys, reinterpret_cast<uint8_t *>(&randnum), sizeof(randnum));
self->rng->funcs->random_bytes(
self, reinterpret_cast<uint8_t *>(&randnum), sizeof(randnum));
return randnum % upper_bound;
},
};
@ -122,8 +121,7 @@ Fuzz_System::Fuzz_System(Fuzz_Data &input)
, ns(std::make_unique<Network>(Network{&fuzz_network_funcs, this}))
, rng(std::make_unique<Random>(Random{&fuzz_random_funcs, this}))
{
sys->mono_time_callback
= [](void *user_data) { return static_cast<Fuzz_System *>(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();