Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Issue 19836 - Excessive probability of UUID collisions in std.uuid.randomUUID #6985

Merged
merged 1 commit into from Apr 29, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 30 additions & 0 deletions std/random.d
Expand Up @@ -1813,6 +1813,8 @@ A singleton instance of the default random number generator
{
static if (isSeedable!(Random, ulong))
result.seed(unpredictableSeed!ulong); // Avoid unnecessary copy.
else static if (size_t.sizeof >= ulong.sizeof && is(Random : MersenneTwisterEngine!Params, Params...))
initMTEngine(result); // 64-bit multiplication is fast, so use a 64-bit seed.
else static if (isSeedable!(Random, uint))
result.seed(unpredictableSeed!uint); // Avoid unnecessary copy.
else
Expand All @@ -1831,6 +1833,34 @@ A singleton instance of the default random number generator
assert(rnd.take(3).sum > 0);
}

/+
Initialize a 32-bit MersenneTwisterEngine from 64 bits of entropy.
This is private and accepts no seed as a parameter, freeing the internal
implementaton from any need for stability across releases.
+/
private void initMTEngine(MTEngine)(scope ref MTEngine mt)
if (is(MTEngine : MersenneTwisterEngine!Params, Params...))
{
pragma(inline, false); // Called no more than once per thread by rndGen.
ulong x = unpredictableSeed!ulong;
alias UIntType = typeof(mt.front());
foreach (size_t i, ref e; mt.state.data)
{
x = (x ^ (x >> 62)) * 6_364_136_223_846_793_005UL + i;
e = cast(UIntType) x;
static if (MTEngine.max != UIntType.max)
{
e &= MTEngine.max;
}
}
mt.state.index = mt.state.data.length - 1;
// double popFront() to guarantee both `mt.state.z`
// and `mt.state.front` are derived from the newly
// set values in `mt.state.data`.
mt.popFront();
mt.popFront();
}

/**
Generates a number between `a` and `b`. The `boundaries`
parameter controls the shape of the interval (open vs. closed on
Expand Down