mirror of
https://github.com/Perl/perl5.git
synced 2026-01-26 08:38:23 +00:00
Clean up, simplify, and re-work Perl_seed(). Fixes #2296
DEBUG_U doesn't work? We'll just use a normal comment for now epoch should be U64
This commit is contained in:
parent
134107b181
commit
76771b2f9a
97
util.c
97
util.c
@ -4573,41 +4573,28 @@ PERL_STATIC_INLINE U32 S_ptr_hash(PTRV u) {
|
||||
return (U32)u;
|
||||
}
|
||||
|
||||
/* Splitmix64 is a simple PRNG and integer hashing function. It was
|
||||
* introducted in 2015: https://gee.cs.oswego.edu/dl/papers/oopsla14.pdf
|
||||
* Examples: https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64
|
||||
*/
|
||||
U64
|
||||
splitmix64(U64 *state)
|
||||
{
|
||||
U64 z = (*state += 0x9e3779b97f4a7c15);
|
||||
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
|
||||
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
|
||||
|
||||
return z ^ (z >> 31);
|
||||
}
|
||||
|
||||
U64
|
||||
Perl_seed(pTHX)
|
||||
{
|
||||
/*
|
||||
* This is really just a quick hack which grabs various garbage
|
||||
* values. It really should be a real hash algorithm which
|
||||
* spreads the effect of every input bit onto every output bit,
|
||||
* if someone who knows about such things would bother to write it.
|
||||
* Might be a good idea to add that function to CORE as well.
|
||||
* No numbers below come from careful analysis or anything here,
|
||||
* except they are primes and SEED_C1 > 1E6 to get a full-width
|
||||
* value from (tv_sec * SEED_C1 + tv_usec). The multipliers should
|
||||
* probably be bigger too.
|
||||
*/
|
||||
#if RANDBITS > 16
|
||||
# define SEED_C1 1000003
|
||||
#define SEED_C4 73819
|
||||
#else
|
||||
# define SEED_C1 25747
|
||||
#define SEED_C4 20639
|
||||
#endif
|
||||
#define SEED_C2 3
|
||||
#define SEED_C3 269
|
||||
#define SEED_C5 26107
|
||||
|
||||
#ifndef PERL_NO_DEV_RANDOM
|
||||
int fd;
|
||||
#endif
|
||||
U32 u;
|
||||
#ifdef HAS_GETTIMEOFDAY
|
||||
struct timeval when;
|
||||
#else
|
||||
Time_t when;
|
||||
#endif
|
||||
/*
|
||||
* Attempt to read from /dev/urandom to generate a pseudo-random number.
|
||||
* If that does not work, or it is unavailable, we fall back to gathering
|
||||
* several state variables and hashing them into a seed value.
|
||||
*/
|
||||
|
||||
/* This test is an escape hatch, this symbol isn't set by Configure. */
|
||||
#ifndef PERL_NO_DEV_RANDOM
|
||||
@ -4617,35 +4604,57 @@ Perl_seed(pTHX)
|
||||
* PERL_RANDOM_DEVICE to it if you'd prefer Perl to block until there
|
||||
* is enough real entropy to fill the seed. */
|
||||
# ifdef __amigaos4__
|
||||
# define PERL_RANDOM_DEVICE "RANDOM:SIZE=4"
|
||||
/* https://wiki.amigaos.net/wiki/AmigaOS_Manual%3A_AmigaDOS_Additional_Amiga_Directories#Random-Handler_(RANDOM:) */
|
||||
# define PERL_RANDOM_DEVICE "RANDOM:"
|
||||
# else
|
||||
# define PERL_RANDOM_DEVICE "/dev/urandom"
|
||||
# endif
|
||||
#endif
|
||||
fd = PerlLIO_open_cloexec(PERL_RANDOM_DEVICE, 0);
|
||||
U64 u;
|
||||
|
||||
int fd = PerlLIO_open_cloexec(PERL_RANDOM_DEVICE, 0);
|
||||
if (fd != -1) {
|
||||
if (PerlLIO_read(fd, (void*)&u, sizeof u) != sizeof u)
|
||||
if (PerlLIO_read(fd, (void*)&u, sizeof u) != sizeof u) {
|
||||
u = 0;
|
||||
}
|
||||
|
||||
PerlLIO_close(fd);
|
||||
if (u)
|
||||
|
||||
if (u) {
|
||||
return u;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We only get this far if /dev/urandom is not available or the read fails.
|
||||
* Grab several state variables and hash those for randomness instead. */
|
||||
|
||||
#ifdef HAS_GETTIMEOFDAY
|
||||
struct timeval when;
|
||||
|
||||
PerlProc_gettimeofday(&when,NULL);
|
||||
u = (U32)SEED_C1 * when.tv_sec + (U32)SEED_C2 * when.tv_usec;
|
||||
/* Milliseconds */
|
||||
U64 epoch = ((U64)when.tv_sec * 1000000) + when.tv_usec;
|
||||
#else
|
||||
Time_t when;
|
||||
|
||||
(void)time(&when);
|
||||
u = (U32)SEED_C1 * when;
|
||||
/* Seconds */
|
||||
U64 epoch = when;
|
||||
#endif
|
||||
u += SEED_C3 * (U32)PerlProc_getpid();
|
||||
u += SEED_C4 * (U32)PTR2UV(PL_stack_sp);
|
||||
#ifndef PLAN9 /* XXX Plan9 assembler chokes on this; fix needed */
|
||||
UV ptruv = PTR2UV(&when);
|
||||
u += SEED_C5 * ptr_hash(ptruv);
|
||||
#endif
|
||||
return u;
|
||||
|
||||
UV pid = PerlProc_getpid();
|
||||
UV time_ptr = PTR2UV(&when);
|
||||
|
||||
/* epoch in microseconds is ~52 bits, PIDs are ~22 bits, PTRs are ~48 bits.
|
||||
* We mix the bits for all three together to get a good spread of entropy */
|
||||
U64 tmp = (time_ptr << 16) | (pid << 8) | (epoch);
|
||||
U64 ret = splitmix64(&tmp);
|
||||
|
||||
/* PerlIO_printf(Perl_debug_log, "XXXX: TIME:%lu PID:%lu PTR:%lu\n", epoch, pid, time_ptr); */
|
||||
/* PerlIO_printf(Perl_debug_log, "SEED: %lu\n", ret); */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user