1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_RAND_UTIL_H_
#define BASE_RAND_UTIL_H_
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <cmath>
#include <concepts>
#include <string>
#include <type_traits>
#include <vector>
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/containers/span.h"
#include "base/gtest_prod_util.h"
#include "base/numerics/clamped_math.h"
#include "base/numerics/safe_conversions.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "third_party/boringssl/src/include/openssl/rand.h"
namespace memory_simulator {
class MemoryHolder;
}
namespace gwp_asan::internal {
class ExtremeLightweightDetectorQuarantineBranch;
}
namespace base {
namespace internal {
void ConfigureBoringSSLBackedRandBytesFieldTrial();
// Returns a random double in range [0, 1). For use in allocator shim to avoid
// infinite recursion. Thread-safe.
BASE_EXPORT double RandDoubleAvoidAllocation();
} // namespace internal
namespace test {
class InsecureRandomGenerator;
} // namespace test
// Returns a random number in range [0, UINT64_MAX]. Thread-safe.
BASE_EXPORT uint64_t RandUint64();
// Returns a random number between min and max (inclusive). Thread-safe.
//
// TODO(crbug.com/40283703): Change from fully-closed to half-closed (i.e.
// exclude `max`) to parallel other APIs here.
BASE_EXPORT int RandInt(int min, int max);
// Returns a random number in range [0, range). Thread-safe.
BASE_EXPORT uint64_t RandGenerator(uint64_t range);
// Returns a random double in range [0, 1). Thread-safe.
BASE_EXPORT double RandDouble();
// Returns a random float in range [0, 1). Thread-safe.
BASE_EXPORT float RandFloat();
// Returns a random bool. Thread-safe.
BASE_EXPORT bool RandBool();
// Returns a random duration in [`start`, `limit`). Thread-safe.
//
// REQUIRES: `start` < `limit`
BASE_EXPORT TimeDelta RandTimeDelta(TimeDelta start, TimeDelta limit);
// Returns a random duration in [`TimeDelta()`, `limit`). Thread-safe.
//
// REQUIRES: `limit.is_positive()`
BASE_EXPORT TimeDelta RandTimeDeltaUpTo(TimeDelta limit);
// Adjusts `value` up or down by a random amount up to `percentage`%, e.g. to
// add noise/jitter. Thread-safe.
//
// More precisely, implements something equivalent to the following pseudocode:
// (1) Computes `max_adjustment = value * percentage / 100` as a double
// (2) If `T` is integral, rounds `max_adjustment`, clamped to what is
// effectively a 65-bit signed value
// (3) Computes `result` as a random value in the range of
// [`value - max_adjustment`, `value + max_adjustment`)
// (4) Checks that the `result` is in the valid range of `T` and returns it
//
// REQUIRES: inputs are finite, `percentage` >= 0
template <typename T>
requires std::floating_point<T>
T RandomizeByPercentage(T value, double percentage) {
CHECK(!std::isinf(value));
CHECK(!std::isnan(value));
CHECK(!std::isinf(percentage));
CHECK_GE(percentage, 0);
return checked_cast<T>(value +
value * (RandDouble() - 0.5) * 2 * percentage / 100);
}
template <typename T>
requires std::integral<T>
T RandomizeByPercentage(T value, double percentage) {
CHECK(!std::isinf(percentage));
CHECK_GE(percentage, 0);
// If `T` is signed and `percentage` is sufficiently large, the maximum
// adjustment may not fit in a `T`. The clamped value described in pseudocode
// step (2) above will always fit in a `uint64_t`, so do math in `uint64_t`s.
const uint64_t abs_value = SafeUnsignedAbs(value);
const uint64_t max_abs_adjustment =
ClampRound<uint64_t>(abs_value * percentage / 100);
if (!max_abs_adjustment) {
return value;
}
uint64_t abs_adjustment = RandGenerator(max_abs_adjustment);
CheckedNumeric<T> checked_value(value);
// Random sign bit for the adjustment.
if (RandBool()) {
// Subtract adjustment.
//
// Be careful to "translate" the adjustment to the other side of `value` (by
// doing the subtraction from `max_abs_adjustment` here) instead of
// "mirroring" it (as would happen if this were omitted). This avoids bias
// and preserves the desired half-closed interval property of the result
// range.
abs_adjustment = max_abs_adjustment - abs_adjustment;
checked_value -= abs_adjustment;
} else {
checked_value += abs_adjustment;
}
return checked_value.ValueOrDie();
}
inline TimeDelta RandomizeByPercentage(TimeDelta value, double percentage) {
CHECK(!value.is_inf());
return Microseconds(
RandomizeByPercentage(value.InMicroseconds(), percentage));
}
// Given input |bits|, convert with maximum precision to a double in
// the range [0, 1). Thread-safe.
BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64_t bits);
// Given input `bits`, convert with maximum precision to a float in the range
// [0, 1). Thread-safe.
BASE_EXPORT float BitsToOpenEndedUnitIntervalF(uint64_t bits);
// Fills `output` with cryptographically secure random data. Thread-safe.
//
// Although implementations are required to use a cryptographically secure
// random number source, code outside of base/ that relies on this should use
// crypto::RandBytes instead to ensure the requirement is easily discoverable.
BASE_EXPORT void RandBytes(span<uint8_t> output);
// Creates a vector of `length` bytes, fills it with random data, and returns
// it. Thread-safe.
//
// Although implementations are required to use a cryptographically secure
// random number source, code outside of base/ that relies on this should use
// crypto::RandBytes instead to ensure the requirement is easily discoverable.
BASE_EXPORT std::vector<uint8_t> RandBytesAsVector(size_t length);
// DEPRECATED. Prefer RandBytesAsVector() above.
// Fills a string of length |length| with random data and returns it.
// Thread-safe.
//
// Note that this is a variation of |RandBytes| with a different return type.
// The returned string is likely not ASCII/UTF-8. Use with care.
//
// Although implementations are required to use a cryptographically secure
// random number source, code outside of base/ that relies on this should use
// crypto::RandBytes instead to ensure the requirement is easily discoverable.
BASE_EXPORT std::string RandBytesAsString(size_t length);
// An STL UniformRandomBitGenerator backed by RandUint64.
class RandomBitGenerator {
public:
using result_type = uint64_t;
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return UINT64_MAX; }
result_type operator()() const { return RandUint64(); }
RandomBitGenerator() = default;
~RandomBitGenerator() = default;
};
class NonAllocatingRandomBitGenerator {
public:
using result_type = uint64_t;
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return UINT64_MAX; }
result_type operator()() const {
uint64_t result;
RAND_get_system_entropy_for_custom_prng(reinterpret_cast<uint8_t*>(&result),
sizeof(result));
return result;
}
NonAllocatingRandomBitGenerator() = default;
~NonAllocatingRandomBitGenerator() = default;
};
// Shuffles [first, last) randomly. Thread-safe.
template <typename Itr>
void RandomShuffle(Itr first, Itr last) {
std::shuffle(first, last, RandomBitGenerator());
}
#if BUILDFLAG(IS_POSIX)
BASE_EXPORT int GetUrandomFD();
#endif
class MetricsSubSampler;
// Fast, insecure pseudo-random number generator.
//
// WARNING: This is not the generator you are looking for. This has significant
// caveats:
// - It is non-cryptographic, so easy to misuse
// - It is neither fork() nor clone()-safe because both RNG's after the
// fork/clone will have the same state and produce the same number stream.
// - Synchronization is up to the client.
//
// Always prefer base::Rand*() above, unless you have a use case where its
// overhead is too high, or system calls are disallowed.
//
// Performance: As of 2021, rough overhead on Linux on a desktop machine of
// base::RandUint64() is ~800ns per call (it performs a system call). On Windows
// it is lower. On the same machine, this generator's cost is ~2ns per call,
// regardless of platform.
//
// This is different from |Rand*()| above as it is guaranteed to never make a
// system call to generate a new number, except to seed it. This should *never*
// be used for cryptographic applications, and is not thread-safe.
//
// It is seeded using base::RandUint64() in the constructor, meaning that it
// doesn't need to be seeded. It can be re-seeded though, with
// ReseedForTesting(). Its period is long enough that it should not need to be
// re-seeded during use.
//
// Uses the XorShift128+ generator under the hood.
class BASE_EXPORT InsecureRandomGenerator {
public:
// Never use outside testing, not enough entropy.
void ReseedForTesting(uint64_t seed);
uint32_t RandUint32() const;
uint64_t RandUint64() const;
// In [0, 1).
double RandDouble() const;
private:
InsecureRandomGenerator();
// State. These are mutable to allow Rand* functions to be declared as const.
// This, in turn, enables use of `MetricsSubSampler` in const contexts.
mutable uint64_t a_ = 0, b_ = 0;
// Before adding a new friend class, make sure that the overhead of
// base::Rand*() is too high, using something more representative than a
// microbenchmark.
// Uses the generator to fill memory pages with random content to make them
// hard to compress, in a simulation tool not bundled with Chrome. CPU
// overhead must be minimized to correctly measure memory effects.
friend class memory_simulator::MemoryHolder;
// Uses the generator to sub-sample metrics.
friend class MetricsSubSampler;
// test::InsecureRandomGenerator can be used for testing.
friend class test::InsecureRandomGenerator;
friend class gwp_asan::internal::ExtremeLightweightDetectorQuarantineBranch;
FRIEND_TEST_ALL_PREFIXES(RandUtilTest,
InsecureRandomGeneratorProducesBothValuesOfAllBits);
FRIEND_TEST_ALL_PREFIXES(RandUtilTest, InsecureRandomGeneratorChiSquared);
FRIEND_TEST_ALL_PREFIXES(RandUtilTest, InsecureRandomGeneratorRandDouble);
FRIEND_TEST_ALL_PREFIXES(RandUtilPerfTest, InsecureRandomRandUint64);
};
// Fast class to randomly sub-sample metrics that are logged in high frequency
// code.
//
// WARNING: This uses InsecureRandomGenerator so all the caveats there apply.
// In particular if a MetricsSubSampler object exists when fork()/clone() is
// called, calls to ShouldSample() on both sides of the fork will return the
// same values, possibly introducing metric bias.
class BASE_EXPORT MetricsSubSampler {
public:
MetricsSubSampler();
bool ShouldSample(double probability) const;
void Reseed();
// Make any call to ShouldSample for any instance of MetricsSubSampler
// return true for testing. Cannot be used in conjunction with
// ScopedNeverSampleForTesting.
class BASE_EXPORT ScopedAlwaysSampleForTesting {
public:
ScopedAlwaysSampleForTesting();
~ScopedAlwaysSampleForTesting();
};
// Make any call to ShouldSample for any instance of MetricsSubSampler
// return false for testing. Cannot be used in conjunction with
// ScopedAlwaysSampleForTesting.
class BASE_EXPORT ScopedNeverSampleForTesting {
public:
ScopedNeverSampleForTesting();
~ScopedNeverSampleForTesting();
};
private:
InsecureRandomGenerator generator_;
};
// Returns true with `probability` using a pseudo-random number generator (or
// always/never returns true if a `ScopedAlwaysSampleForTesting` or
// `ScopedNeverSampleForTesting` is in scope). Valid values for `probability`
// are in range [0, 1].
//
// This function is intended for sub-sampled metric recording only. Do not use
// it for any other purpose, especially where cryptographic randomness is
// required.
//
// Uses a thread local MetricsSubSampler.
BASE_EXPORT bool ShouldRecordSubsampledMetric(double probability);
// Reseeds the MetricsSubsampler used by ShouldRecordSubsampledMetric. Used
// after forking a zygote to avoid having multiple processes sharing initial
// RNG state.
BASE_EXPORT void ReseedSharedMetricsSubsampler();
} // namespace base
#endif // BASE_RAND_UTIL_H_
|