Add gRandom and gArbitrary and initFuzz
This commit is contained in:
143
Internal.h
143
Internal.h
@@ -265,6 +265,123 @@ bool operator!=(const ArenaAlloc<T> &lhs, const ArenaAlloc<U> &rhs) {
|
|||||||
|
|
||||||
// ==================== END ARENA IMPL ====================
|
// ==================== END ARENA IMPL ====================
|
||||||
|
|
||||||
|
// ==================== BEGIN RANDOM IMPL ====================
|
||||||
|
|
||||||
|
struct Random {
|
||||||
|
// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
|
||||||
|
// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
|
||||||
|
//
|
||||||
|
// Modified - mostly c -> c++
|
||||||
|
Random() = default;
|
||||||
|
|
||||||
|
Random(uint64_t initState, uint64_t initSeq) {
|
||||||
|
pcg32_srandom_r(initState, initSeq);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draws from a uniform distribution of uint32_t's
|
||||||
|
uint32_t next() {
|
||||||
|
auto result = next_;
|
||||||
|
next_ = pcg32_random_r();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draws from a uniform distribution of [0, s). From
|
||||||
|
/// https://arxiv.org/pdf/1805.10941.pdf
|
||||||
|
uint32_t bounded(uint32_t s) {
|
||||||
|
assert(s != 0);
|
||||||
|
uint32_t x = next();
|
||||||
|
auto m = uint64_t(x) * uint64_t(s);
|
||||||
|
auto l = uint32_t(m);
|
||||||
|
if (l < s) {
|
||||||
|
uint32_t t = -s % s;
|
||||||
|
while (l < t) {
|
||||||
|
x = next();
|
||||||
|
m = uint64_t(x) * uint64_t(s);
|
||||||
|
l = uint32_t(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t result = m >> 32;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fill `bytes` with `size` random hex bytes
|
||||||
|
void randomHex(uint8_t *bytes, int size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t pcg32_random_r() {
|
||||||
|
uint64_t oldState = state;
|
||||||
|
// Advance internal state
|
||||||
|
state = oldState * 6364136223846793005ULL + inc;
|
||||||
|
// Calculate output function (XSH RR), uses old state for max ILP
|
||||||
|
uint32_t xorShifted = ((oldState >> 18u) ^ oldState) >> 27u;
|
||||||
|
uint32_t rot = oldState >> 59u;
|
||||||
|
return (xorShifted >> rot) | (xorShifted << ((-rot) & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seed the rng. Specified in two parts, state initializer and a
|
||||||
|
// sequence selection constant (a.k.a. stream id)
|
||||||
|
void pcg32_srandom_r(uint64_t initstate, uint64_t initSeq) {
|
||||||
|
state = 0U;
|
||||||
|
inc = (initSeq << 1u) | 1u;
|
||||||
|
pcg32_random_r();
|
||||||
|
state += initstate;
|
||||||
|
pcg32_random_r();
|
||||||
|
}
|
||||||
|
uint32_t next_{};
|
||||||
|
// RNG state. All values are possible.
|
||||||
|
uint64_t state{};
|
||||||
|
// Controls which RNG sequence (stream) is selected. Must *always* be odd.
|
||||||
|
uint64_t inc{};
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void Random::randomHex(uint8_t *bytes, int size) {
|
||||||
|
int i = 0;
|
||||||
|
while (i + 8 < size) {
|
||||||
|
uint32_t r = next();
|
||||||
|
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
||||||
|
r >>= 4;
|
||||||
|
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
||||||
|
r >>= 4;
|
||||||
|
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
||||||
|
r >>= 4;
|
||||||
|
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
||||||
|
r >>= 4;
|
||||||
|
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
||||||
|
r >>= 4;
|
||||||
|
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
||||||
|
r >>= 4;
|
||||||
|
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
||||||
|
r >>= 4;
|
||||||
|
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
||||||
|
}
|
||||||
|
uint32_t r = next();
|
||||||
|
while (i < size) {
|
||||||
|
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
||||||
|
r >>= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Random seededRandom() {
|
||||||
|
FILE *f = fopen("/dev/urandom", "r");
|
||||||
|
if (f == nullptr) {
|
||||||
|
fprintf(stderr, "Failed to open /dev/urandom\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
uint64_t seed[2];
|
||||||
|
if (fread(seed, sizeof(seed[0]), sizeof(seed) / sizeof(seed[0]), f) !=
|
||||||
|
sizeof(seed) / sizeof(seed[0])) {
|
||||||
|
fprintf(stderr, "Failed to read from /dev/urandom\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
return Random{seed[0], seed[1]};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline thread_local Random gRandom = seededRandom();
|
||||||
|
|
||||||
|
// ==================== END RANDOM IMPL ====================
|
||||||
|
|
||||||
// ==================== BEGIN ARBITRARY IMPL ====================
|
// ==================== BEGIN ARBITRARY IMPL ====================
|
||||||
|
|
||||||
/// Think of `Arbitrary` as an attacker-controlled random number generator.
|
/// Think of `Arbitrary` as an attacker-controlled random number generator.
|
||||||
@@ -290,16 +407,6 @@ struct Arbitrary {
|
|||||||
/// Draws an arbitrary element from [0, s)
|
/// Draws an arbitrary element from [0, s)
|
||||||
uint32_t bounded(uint32_t s);
|
uint32_t bounded(uint32_t s);
|
||||||
|
|
||||||
/// Fill `bytes` with `size` arbitrary bytes
|
|
||||||
void randomBytes(uint8_t *bytes, int size) {
|
|
||||||
int toFill = std::min<int>(size, bytecode.size());
|
|
||||||
if (toFill > 0) {
|
|
||||||
memcpy(bytes, bytecode.data(), toFill);
|
|
||||||
}
|
|
||||||
bytecode = bytecode.subspan(toFill, bytecode.size() - toFill);
|
|
||||||
memset(bytes + toFill, 0, size - toFill);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fill `bytes` with `size` random hex bytes
|
/// Fill `bytes` with `size` random hex bytes
|
||||||
void randomHex(uint8_t *bytes, int size) {
|
void randomHex(uint8_t *bytes, int size) {
|
||||||
for (int i = 0; i < size;) {
|
for (int i = 0; i < size;) {
|
||||||
@@ -312,13 +419,6 @@ struct Arbitrary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class = std::enable_if_t<std::is_trivially_copyable_v<T>>>
|
|
||||||
T randT() {
|
|
||||||
T t;
|
|
||||||
randomBytes((uint8_t *)&t, sizeof(T));
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasEntropy() const { return bytecode.size() != 0; }
|
bool hasEntropy() const { return bytecode.size() != 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -381,6 +481,15 @@ inline uint32_t Arbitrary::bounded(uint32_t s) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Arbitrary gArbitrary;
|
||||||
|
|
||||||
|
inline void initFuzz(const uint8_t *data, size_t size) {
|
||||||
|
gArbitrary = Arbitrary{{data, size}};
|
||||||
|
uint64_t state = gArbitrary.next();
|
||||||
|
uint64_t seq = gArbitrary.next();
|
||||||
|
gRandom = Random{state, seq};
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== END ARBITRARY IMPL ====================
|
// ==================== END ARBITRARY IMPL ====================
|
||||||
|
|
||||||
// GCOVR_EXCL_STOP
|
// GCOVR_EXCL_STOP
|
||||||
|
120
VersionedMap.cpp
120
VersionedMap.cpp
@@ -63,117 +63,6 @@ void munmapSafe(void *ptr, size_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Random {
|
|
||||||
// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
|
|
||||||
// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
|
|
||||||
//
|
|
||||||
// Modified - mostly c -> c++
|
|
||||||
Random() = default;
|
|
||||||
|
|
||||||
Random(uint64_t initState, uint64_t initSeq) {
|
|
||||||
pcg32_srandom_r(initState, initSeq);
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Draws from a uniform distribution of uint32_t's
|
|
||||||
uint32_t next() {
|
|
||||||
auto result = next_;
|
|
||||||
next_ = pcg32_random_r();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Draws from a uniform distribution of [0, s). From
|
|
||||||
/// https://arxiv.org/pdf/1805.10941.pdf
|
|
||||||
uint32_t bounded(uint32_t s) {
|
|
||||||
assert(s != 0);
|
|
||||||
uint32_t x = next();
|
|
||||||
auto m = uint64_t(x) * uint64_t(s);
|
|
||||||
auto l = uint32_t(m);
|
|
||||||
if (l < s) {
|
|
||||||
uint32_t t = -s % s;
|
|
||||||
while (l < t) {
|
|
||||||
x = next();
|
|
||||||
m = uint64_t(x) * uint64_t(s);
|
|
||||||
l = uint32_t(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32_t result = m >> 32;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fill `bytes` with `size` random hex bytes
|
|
||||||
void randomHex(uint8_t *bytes, int size);
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t pcg32_random_r() {
|
|
||||||
uint64_t oldState = state;
|
|
||||||
// Advance internal state
|
|
||||||
state = oldState * 6364136223846793005ULL + inc;
|
|
||||||
// Calculate output function (XSH RR), uses old state for max ILP
|
|
||||||
uint32_t xorShifted = ((oldState >> 18u) ^ oldState) >> 27u;
|
|
||||||
uint32_t rot = oldState >> 59u;
|
|
||||||
return (xorShifted >> rot) | (xorShifted << ((-rot) & 31));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seed the rng. Specified in two parts, state initializer and a
|
|
||||||
// sequence selection constant (a.k.a. stream id)
|
|
||||||
void pcg32_srandom_r(uint64_t initstate, uint64_t initSeq) {
|
|
||||||
state = 0U;
|
|
||||||
inc = (initSeq << 1u) | 1u;
|
|
||||||
pcg32_random_r();
|
|
||||||
state += initstate;
|
|
||||||
pcg32_random_r();
|
|
||||||
}
|
|
||||||
uint32_t next_{};
|
|
||||||
// RNG state. All values are possible.
|
|
||||||
uint64_t state{};
|
|
||||||
// Controls which RNG sequence (stream) is selected. Must *always* be odd.
|
|
||||||
uint64_t inc{};
|
|
||||||
};
|
|
||||||
|
|
||||||
void Random::randomHex(uint8_t *bytes, int size) {
|
|
||||||
int i = 0;
|
|
||||||
while (i + 8 < size) {
|
|
||||||
uint32_t r = next();
|
|
||||||
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
|
||||||
r >>= 4;
|
|
||||||
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
|
||||||
r >>= 4;
|
|
||||||
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
|
||||||
r >>= 4;
|
|
||||||
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
|
||||||
r >>= 4;
|
|
||||||
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
|
||||||
r >>= 4;
|
|
||||||
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
|
||||||
r >>= 4;
|
|
||||||
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
|
||||||
r >>= 4;
|
|
||||||
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
|
||||||
}
|
|
||||||
uint32_t r = next();
|
|
||||||
while (i < size) {
|
|
||||||
bytes[i++] = "0123456789abcdef"[r & 0b1111];
|
|
||||||
r >>= 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Random seededRandom() {
|
|
||||||
FILE *f = fopen("/dev/urandom", "r");
|
|
||||||
if (f == nullptr) {
|
|
||||||
fprintf(stderr, "Failed to open /dev/urandom\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
uint64_t seed[2];
|
|
||||||
if (fread(seed, sizeof(seed[0]), sizeof(seed) / sizeof(seed[0]), f) !=
|
|
||||||
sizeof(seed) / sizeof(seed[0])) {
|
|
||||||
fprintf(stderr, "Failed to read from /dev/urandom\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
return Random{seed[0], seed[1]};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace weaselab {
|
namespace weaselab {
|
||||||
|
|
||||||
// 96 is enough for an entire search path in a tree with a size that
|
// 96 is enough for an entire search path in a tree with a size that
|
||||||
@@ -773,7 +662,7 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
|||||||
// Prepare new node
|
// Prepare new node
|
||||||
uint32_t node = newNode(
|
uint32_t node = newNode(
|
||||||
pointVersion, rangeVersion, key.p, key.len, val->p, val->len,
|
pointVersion, rangeVersion, key.p, key.len, val->p, val->len,
|
||||||
inserted ? random.next() : mm.base[finger.backNode()].entry->priority);
|
inserted ? gRandom.next() : mm.base[finger.backNode()].entry->priority);
|
||||||
if (!inserted) {
|
if (!inserted) {
|
||||||
auto &n = mm.base[node];
|
auto &n = mm.base[node];
|
||||||
n.pointer[0] = child<std::memory_order_relaxed>(finger.backNode(), false,
|
n.pointer[0] = child<std::memory_order_relaxed>(finger.backNode(), false,
|
||||||
@@ -945,13 +834,6 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
|||||||
void firstGeq(const Key *key, const int64_t *version, Iterator *iterator,
|
void firstGeq(const Key *key, const int64_t *version, Iterator *iterator,
|
||||||
int count) const;
|
int count) const;
|
||||||
|
|
||||||
Random random =
|
|
||||||
#ifndef NDEBUG
|
|
||||||
{};
|
|
||||||
#else
|
|
||||||
seededRandom();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MemManager mm;
|
MemManager mm;
|
||||||
RootSet roots;
|
RootSet roots;
|
||||||
// Only meaningful within the callstack of `addMutations`
|
// Only meaningful within the callstack of `addMutations`
|
||||||
|
Reference in New Issue
Block a user