blob: 61cedc8a2d6669cdcb1c1ddae46b19fbb18ff7f2 [file]
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FUZZTEST_FUZZTEST_FUZZING_BIT_GEN_H_
#define FUZZTEST_FUZZTEST_FUZZING_BIT_GEN_H_
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include "absl/base/attributes.h"
#include "absl/base/fast_type_id.h"
#include "absl/numeric/int128.h"
#include "absl/random/mocking_access.h"
#include "absl/types/span.h"
namespace fuzztest {
/// FuzzingBitGen is a BitGen instance which uses the Abseil mock mechanisms
/// to return distribution-specific variates based on the underlying control
/// and data streams. The specific sequence generated by a FuzzingBitGen may
/// vary due to the underlying code paths and whether implementation details
/// change, such as adding support for new distributions, etc.
///
/// The `control stream` is a sequence of control bytes which modifies the
/// behavior of the mocked distribution functions, such as returning min,
/// max, mean, or alternate values. When the control stream is exhausted,
/// it is not reused; it behaves as though it were zero-padded.
///
/// The `data_stream` is used to provide the random values for the mocked
/// distribution functions, as well as an internal URBG used for non-mocked
/// functions, such as std::shuffle(...). When the data stream is exhausted,
/// it is *not* reused (wrapped around), instead the internal URBG is used as
/// the source of random variates.
///
/// The `seed_value` is used to seed the internal URBG.
///
/// NOTE: After both control and data streams are exhausted, FuzzingBitGen falls
/// back to an internal LCG PRNG, which should avoid infinite loops in fuzzed
/// functions.
///
/// This type is thread-compatible, but not thread-safe.
class FuzzingBitGen {
public:
// Create a FuzzingBitGen from an unowned fuzzed `data_stream` source, an
// optional `control_stream` source, and an optional `seed_value`.
// Both streams must outlive the FuzzingBitGen.
explicit FuzzingBitGen(
absl::Span<const uint8_t> data_stream ABSL_ATTRIBUTE_LIFETIME_BOUND,
absl::Span<const uint8_t> control_stream ABSL_ATTRIBUTE_LIFETIME_BOUND,
uint64_t seed_value);
explicit FuzzingBitGen(
absl::Span<const uint8_t> data_stream ABSL_ATTRIBUTE_LIFETIME_BOUND);
FuzzingBitGen(const FuzzingBitGen&) = delete;
FuzzingBitGen& operator=(const FuzzingBitGen&) = delete;
FuzzingBitGen(FuzzingBitGen&&) = default;
FuzzingBitGen& operator=(FuzzingBitGen&&) = default;
using result_type = uint64_t;
static constexpr result_type(min)() {
return (std::numeric_limits<result_type>::min)();
}
static constexpr result_type(max)() {
return (std::numeric_limits<result_type>::max)();
}
void seed(result_type seed_value = 0);
result_type operator()();
private:
// Consumes up to x bytes from the data stream, or if there are no remaining
// bytes, returns bytes from the internal LCG PRNG.
// `result` points to a buffer that is pre-initialized as the entire buffer
// may not be overwritten.
void DataStreamFn(bool use_lcg, void* result, size_t result_size);
// InvokeMock meets the requirements of absl::BitGenRef::InvokeMock.
// This method detects whether the key has been registered as supported,
// and, if so, returns a value derived from `data_stream_`.
bool InvokeMock(absl::FastTypeIdType key_id, void* args_tuple, void* result);
absl::uint128 urbg_state_ = 0;
absl::Span<const uint8_t> control_stream_;
absl::Span<const uint8_t> data_stream_;
friend class ::absl::RandomMockingAccess; // for InvokeMock
};
} // namespace fuzztest
#endif // FUZZTEST_FUZZTEST_FUZZING_BIT_GEN_H_