blob: b66989e9f0c574ef63ce3c9ba98f9dbafada069d [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_FUZZING_FIDL_SIGNAL_COORDINATOR_H_
#define SRC_LIB_FUZZING_FIDL_SIGNAL_COORDINATOR_H_
#include <lib/fxl/macros.h>
#include <lib/zx/eventpair.h>
#include <zircon/types.h>
#include <thread>
namespace fuzzing {
// This enum renames some Zircon user signals to associate them with certain actions performed by
// the libFuzzer engine.
enum Signal : zx_signals_t {
// Corresponds to the start of a fuzzing iteration, as in |fuzzer::Fuzzer::ExecuteCallback|.
kExecuteCallback = ZX_USER_SIGNAL_0,
// Corresponds to the end of a fuzzing iteration, similar to the call to libFuzzer's
// |fuzzer::TracePC::CollectFeatures| in |fuzzer::Fuzzer::RunOne|.
kCollectCoverage = ZX_USER_SIGNAL_1,
// Instructs the remote process to perform an iteration checking for leaks.
kTryDetectingALeak = ZX_USER_SIGNAL_0 | ZX_USER_SIGNAL_2,
// Suggests to the fuzzer engine that a leak is likely in the previous iteration.
kLeakDetected = ZX_USER_SIGNAL_1 | ZX_USER_SIGNAL_2,
// Indicates the fuzzer is shutting done and end-of-process leak detection should be performed.
kDetectLeaksAtExit = ZX_USER_SIGNAL_2,
};
// This class wraps an eventpair and thread to present a simple way for one process to signal
// another, and have that process respond. This class is used in this library with
// |fuzzing::Signals|.
class SignalCoordinator final {
public:
SignalCoordinator() = default;
~SignalCoordinator();
// Both |Create| and |Pair| take an |on_signal| parameter, which should be callable with the
// signature: bool on_signal(zx_signals_t signals);
//
// This will be called when a the other end of the event pair sends a Zircon user signal to this
// end. If this method returns false, the wait loop will exit. When the wait loop exits for any
// reason, this method will be called one final time with |ZX_EVENTPAIR_PEER_CLOSED|.
// Creates an event pair and returns one end via |out|. If this object was previously created or
// linked, it is first reset. See the above note on |on_signal|.
template <typename SignalHandler>
void Create(zx::eventpair* out, SignalHandler on_signal);
// Takes one end of an event pair and starts a thread to listen for signals on it. If this object
// was previously created or linked, it is first reset. See the above note on |on_signal|.
template <typename SignalHandler>
void Pair(zx::eventpair paired, SignalHandler on_signal);
// Send one or more Zircon user signals to the other end of the eventpair. Returns true if the
// signal was sent, or false if the other end disconnected/reset.
bool SignalPeer(Signal signal);
// Blocks and joins the wait loop thread. This method does not reset the eventpair, so it should
// only be used when one side is certain the other is about to break the connection.
void Join();
// Calls |Join| and resets this object to its initial state, effectively breaking the connection.
void Reset();
private:
void CreateImpl(zx::eventpair* out);
void PairImpl(zx::eventpair paired);
// Returns `ZX_EVENTPAIR_PEER_CLOSED` if disconnected, or blocks until a signal is received and
// returns it.
zx_signals_t WaitOne();
template <typename SignalHandler>
void WaitLoop(SignalHandler on_signal);
zx::eventpair paired_;
std::thread wait_loop_;
FXL_DISALLOW_COPY_ASSIGN_AND_MOVE(SignalCoordinator);
};
// Templated method implementations.
template <typename SignalHandler>
void SignalCoordinator::Create(zx::eventpair* out, SignalHandler on_signal) {
CreateImpl(out);
WaitLoop(on_signal);
}
template <typename SignalHandler>
void SignalCoordinator::Pair(zx::eventpair paired, SignalHandler on_signal) {
PairImpl(std::move(paired));
WaitLoop(on_signal);
}
template <typename SignalHandler>
void SignalCoordinator::WaitLoop(SignalHandler on_signal) {
wait_loop_ = std::thread([this, on_signal]() {
zx_signals_t observed;
do {
observed = WaitOne();
} while (observed != ZX_EVENTPAIR_PEER_CLOSED && on_signal(observed));
paired_.reset();
on_signal(ZX_EVENTPAIR_PEER_CLOSED);
});
}
} // namespace fuzzing
#endif // SRC_LIB_FUZZING_FIDL_SIGNAL_COORDINATOR_H_