Skip to content

Commit

Permalink
refactor: Avoid static_cast in Fuzz_System functions.
Browse files Browse the repository at this point in the history
Declutters the fuzz system code a bit, hiding the cast behind a `!`
operator.
  • Loading branch information
iphydf committed Apr 10, 2022
1 parent 616bd63 commit 27c27b7
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 20 deletions.
5 changes: 4 additions & 1 deletion testing/fuzzing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
2 changes: 1 addition & 1 deletion testing/fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
69 changes: 69 additions & 0 deletions testing/fuzzing/func_conversion.h
Original file line number Diff line number Diff line change
@@ -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
34 changes: 16 additions & 18 deletions testing/fuzzing/fuzz_support.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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; },
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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;
},
};
Expand All @@ -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();
Expand Down

0 comments on commit 27c27b7

Please sign in to comment.