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

rand() on Windows only uses 15 bits of entropy #12620

Closed
p5pRT opened this issue Nov 27, 2012 · 153 comments
Closed

rand() on Windows only uses 15 bits of entropy #12620

p5pRT opened this issue Nov 27, 2012 · 153 comments

Comments

@p5pRT
Copy link

p5pRT commented Nov 27, 2012

Migrated from rt.perl.org#115928 (status was 'resolved')

Searchable as RT115928$

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From Perl@ResonatorSoft.org

Created by Perl@ResonatorSoft.org

The Win32 version of Perl doesn't seem to generate random numbers
very well at all, especially in comparison to the Linux version.

Here's an example script detailing the problem​:

my %nums;
my $cnt = 0;
foreach my $i (1 .. 1_000_000) {
  my $num = rand;
  $cnt++ if ($nums{$num});
  $nums{$num} = 1;
}
print "$cnt out of 1,000,000\n";

The purpose of the script is to reveal how many duplicate numbers
were generated out of a random sample of one million total numbers.
For Windows, this will output "967232 out of 1,000,000" every time.
In other words, there are only 32768 possible combinations of
"between 0 and 1" floats that rand() will generate.

If I test this same script on a Debian Linux box, I actually get no
dupes, meaning that it has a MUCH higher entropy.

Perl Info

Flags:
    category=core
    severity=medium

Site configuration information for perl 5.16.0:

Configured by strawberry-perl at Mon May 21 22:08:30 2012.

Summary of my perl5 (revision 5 version 16 subversion 0) configuration:

  Platform:
    osname=MSWin32, osvers=4.0, archname=MSWin32-x86-multi-thread
    uname='Win32 strawberry-perl 5.16.0.1 #1 Mon May 21 22:07:30 2012 i386'
    config_args='undef'
    hint=recommended, useposix=true, d_sigaction=undef
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=undef, use64bitall=undef, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='gcc', ccflags =' -s -O2 -DWIN32  -DPERL_TEXTMODE_SCRIPTS
-DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -fno-strict-aliasing
-mms-bitfields',
    optimize='-s -O2',
    cppflags='-DWIN32'
    ccversion='', gccversion='4.6.3', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='long
long', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='g++', ldflags ='-s -L"C:\strawberry\perl\lib\CORE"
-L"C:\strawberry\c\lib"'
    libpth=C:\strawberry\c\lib C:\strawberry\c\i686-w64-mingw32\lib
    libs=-lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32
-ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32
-lmpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32
    perllibs=-lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool
-lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid
-lws2_32 -lmpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32
    libc=, so=dll, useshrplib=true, libperl=libperl516.a
    gnulibc_version=''
  Dynamic Linking:
    dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' '
    cccdlflags=' ', lddlflags='-mdll -s
-L"C:\strawberry\perl\lib\CORE" -L"C:\strawberry\c\lib"'

Locally applied patches:



@INC for perl 5.16.0:
    C:/STRAWBERRY/perl/site/lib/MSWin32-x86-multi-thread
    C:/STRAWBERRY/perl/site/lib
    C:/STRAWBERRY/perl/vendor/lib
    C:/STRAWBERRY/perl/lib
    .


Environment for perl 5.16.0:
    HOME (unset)
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=C:\Windows\SYSTEM32;C:\Windows;C:\Windows\SYSTEM32\WBEM;C:\Windows\SYSTEM32\WINDOWSPOWERSHELL\V1.0\;C:\STRAWBERRY\C\BIN;C:\STRAWBERRY\PERL\SITE\BIN;C:\STRAWBERRY\PERL\BIN;C:\CYGWIN\BIN;C:\CYGWIN\USR\BIN;C:\Program
Files\TortoiseSVN\bin;C:\Program Files\Graphviz 2.28\bin;C:\Program
Files\TortoiseGit\bin;c:\Program Files\Microsoft SQL
Server\100\Tools\Binn\VSShell\Common7\IDE\;c:\Program Files\Microsoft
SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft Visual Studio
9.0\Common7\IDE\PrivateAssemblies\;c:\Program Files\Microsoft SQL
Server\100\DTS\Binn\;C:\Program Files\Nmap
    PERL_BADLANG (unset)
    SHELL (unset)

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From @wchristian

I replicated the behavior with ActivePerl v5.12.4 (MSWin32-x86-multi-
thread).

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From @Leont

On Tue, Nov 27, 2012 at 3​:59 PM, Perl@​ResonatorSoft.org
<perlbug-followup@​perl.org> wrote​:

The Win32 version of Perl doesn't seem to generate random numbers
very well at all, especially in comparison to the Linux version.

Here's an example script detailing the problem​:

my %nums;
my $cnt = 0;
foreach my $i (1 .. 1_000_000) {
my $num = rand;
$cnt++ if ($nums{$num});
$nums{$num} = 1;
}
print "$cnt out of 1,000,000\n";

The purpose of the script is to reveal how many duplicate numbers
were generated out of a random sample of one million total numbers.
For Windows, this will output "967232 out of 1,000,000" every time.
In other words, there are only 32768 possible combinations of
"between 0 and 1" floats that rand() will generate.

If I test this same script on a Debian Linux box, I actually get no
dupes, meaning that it has a MUCH higher entropy.

Perl already chooses between a bunch of random number sources. If
there's something obviously better available we could use that.

That said, I don't really think this is really severity=medium. rand()
doesn't make any promises on strength, and if you need something
stronger there are modules on CPAN that can provide just that.

Leon

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From @wchristian

On Tue Nov 27 07​:19​:53 2012, LeonT wrote​:

If
there's something obviously better available we could use that.

On Windows XP and higher, there is RtlGenRandom, would that fit the bill?

http​://msdn.microsoft.com/en-us/library/aa387694(v=vs.80).aspx
http​://blogs.msdn.com/b/michael_howard/archive/2005/01/14/353379.aspx

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From @Leont

On Tue, Nov 27, 2012 at 4​:40 PM, Christian Walde via RT
<perlbug-followup@​perl.org> wrote​:

If there's something obviously better available we could use that.

On Windows XP and higher, there is RtlGenRandom, would that fit the bill?

http​://msdn.microsoft.com/en-us/library/aa387694(v=vs.80).aspx
http​://blogs.msdn.com/b/michael_howard/archive/2005/01/14/353379.aspx

Looks workable, though it's linking is horrible even by Windows standards.

Leon

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From BitCard@ResonatorSoft.org

On Tue Nov 27 07​:49​:28 2012, LeonT wrote​:

Looks workable, though it's linking is horrible even by Windows
standards.

BTW, what does Perl currently use for random functionality on Windows?
Honestly, I'm surprised that Windows library routines have that few
combinations.

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From @wchristian

On Tue Nov 27 07​:49​:28 2012, LeonT wrote​:

On Tue, Nov 27, 2012 at 4​:40 PM, Christian Walde via RT
<perlbug-followup@​perl.org> wrote​:

If there's something obviously better available we could use that.

On Windows XP and higher, there is RtlGenRandom, would that fit the
bill?

http​://msdn.microsoft.com/en-us/library/aa387694(v=vs.80).aspx
http​://blogs.msdn.com/b/michael_howard/
archive/2005/01/14/353379.aspx

Looks workable, though it's linking is horrible even by Windows
standards.

Well, as the doc says, if you don't mind a bit of extra memory use, you
can use CryptGenRandom [ http​://msdn.microsoft.com/en-us/library/
aa379942(v=vs.85).aspx ] as a source. Am i remembering that right that
Windows XP is the oldest Windows supported by Perl? Because if so, then
that should be no issue.

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From @wchristian

On Tue Nov 27 07​:53​:01 2012, SineSwiper wrote​:

On Tue Nov 27 07​:49​:28 2012, LeonT wrote​:

Looks workable, though it's linking is horrible even by Windows
standards.

BTW, what does Perl currently use for random functionality on Windows?
Honestly, I'm surprised that Windows library routines have that few
combinations.

Windows currently supplies a rand() in the stdlib that uses 15 bits and
is only meant as a sort of placeholder, since you are meant to select
your own random generator if you actually care about it. Looks like Perl
simply uses that straight-up.

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From @craigberry

On Tue, Nov 27, 2012 at 10​:11 AM, Christian Walde via RT
<perlbug-followup@​perl.org> wrote​:

On Tue Nov 27 07​:53​:01 2012, SineSwiper wrote​:

On Tue Nov 27 07​:49​:28 2012, LeonT wrote​:

Looks workable, though it's linking is horrible even by Windows
standards.

BTW, what does Perl currently use for random functionality on Windows?
Honestly, I'm surprised that Windows library routines have that few
combinations.

Windows currently supplies a rand() in the stdlib that uses 15 bits and
is only meant as a sort of placeholder, since you are meant to select
your own random generator if you actually care about it. Looks like Perl
simply uses that straight-up.

It might be as simple as changing the configuration code (e.g., in
win32/config_H.vc and friends) that looks like​:

#define Drand01()
(rand()/(double)((unsigned)1<<RANDBITS)) /**/
#define Rand_seed_t unsigned /**/
#define seedDrand01(x) srand((Rand_seed_t)x) /**/
#define RANDBITS 15 /**/

to point to something more capable.

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From @kmx

On 27.11.2012 16​:40, Christian Walde via RT wrote​:

On Tue Nov 27 07​:19​:53 2012, LeonT wrote​:

If
there's something obviously better available we could use that.
On Windows XP and higher, there is RtlGenRandom, would that fit the bill?

http​://msdn.microsoft.com/en-us/library/aa387694(v=vs.80).aspx
http​://blogs.msdn.com/b/michael_howard/archive/2005/01/14/353379.aspx

What about CryptGenRandom (available on WinXP+)

{
  BYTE randomdata[256];
  HCRYPTPROV hCryptProv = 0;
  if (CryptAcquireContextW(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
  if (CryptGenRandom(hCryptProv, sizeof(randomdata), randomdata)) {
  /* success */
  }
  else {
  /* failure */
  }
  CryptReleaseContext(hCryptProv, 0);
  }
}

http​://msdn.microsoft.com/en-us/library/windows/desktop/aa379942%28v=vs.85%29.aspx

--
kmx

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From @demerphq

On 27 November 2012 20​:43, kmx <kmx@​atlas.cz> wrote​:

On 27.11.2012 16​:40, Christian Walde via RT wrote​:

On Tue Nov 27 07​:19​:53 2012, LeonT wrote​:

If
there's something obviously better available we could use that.

On Windows XP and higher, there is RtlGenRandom, would that fit the bill?

http​://msdn.microsoft.com/en-us/library/aa387694(v=vs.80).aspx
http​://blogs.msdn.com/b/michael_howard/archive/2005/01/14/353379.aspx

What about CryptGenRandom (available on WinXP+)

{
BYTE randomdata[256];
HCRYPTPROV hCryptProv = 0;
if (CryptAcquireContextW(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
if (CryptGenRandom(hCryptProv, sizeof(randomdata), randomdata)) {
/* success */
}
else {
/* failure */
}
CryptReleaseContext(hCryptProv, 0);
}
}

http​://msdn.microsoft.com/en-us/library/windows/desktop/aa379942%28v=vs.85%29.aspx

Just curious but wouldnt something like that be pretty slow?

I would think that ideally the Win32 version of Perl should "out of
the box" have a reasonably fast RNG.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2012

From @kmx

On 27.11.2012 20​:52, demerphq wrote​:

On 27 November 2012 20​:43, kmx <kmx@​atlas.cz> wrote​:

On 27.11.2012 16​:40, Christian Walde via RT wrote​:

On Tue Nov 27 07​:19​:53 2012, LeonT wrote​:

If
there's something obviously better available we could use that.
On Windows XP and higher, there is RtlGenRandom, would that fit the bill?

http​://msdn.microsoft.com/en-us/library/aa387694(v=vs.80).aspx
http​://blogs.msdn.com/b/michael_howard/archive/2005/01/14/353379.aspx

What about CryptGenRandom (available on WinXP+)

{
BYTE randomdata[256];
HCRYPTPROV hCryptProv = 0;
if (CryptAcquireContextW(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
if (CryptGenRandom(hCryptProv, sizeof(randomdata), randomdata)) {
/* success */
}
else {
/* failure */
}
CryptReleaseContext(hCryptProv, 0);
}
}

http​://msdn.microsoft.com/en-us/library/windows/desktop/aa379942%28v=vs.85%29.aspx

Just curious but wouldnt something like that be pretty slow?

I would think that ideally the Win32 version of Perl should "out of
the box" have a reasonably fast RNG.

[resending as I forget to Cc​: the list]

CryptGenRandom itself is IMO pretty fast the trouble might be with the time
spent in CryptAcquireContextW/CryptReleaseContext.

--
kmx

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2012

From @bulk88

On Tue Nov 27 08​:11​:01 2012, Mithaldu wrote​:

On Tue Nov 27 07​:53​:01 2012, SineSwiper wrote​:

On Tue Nov 27 07​:49​:28 2012, LeonT wrote​:

Looks workable, though it's linking is horrible even by Windows
standards.

BTW, what does Perl currently use for random functionality on Windows?
Honestly, I'm surprised that Windows library routines have that few
combinations.

Windows currently supplies a rand() in the stdlib that uses 15 bits and
is only meant as a sort of placeholder, since you are meant to select
your own random generator if you actually care about it. Looks like Perl
simply uses that straight-up.

Why not call the CRT's rand twice or thrice, once for low 15 bits, 2nd
for high 15 bits, and 3rd for remaining 2?

This is the implementation of rand in MS's CRT
http​://code.google.com/searchframe#S3vzerue4i0/trunk/reactos/lib/sdk/crt/math/rand.c&type=cs&l=10
. ntdll's RtlRandom and RtlRandomEx are similar to CRT's rand. They make
no further calls. Going through RtlGenRandom or anything else in advapi
will be atleast a dozen if not a 100 times slower (or more, I didn't
benchmark it, I know it is 100s of calls tho and eventually an
ioctl/DeviceIoControl to ksecdd.sys driver for the randomness) by my
educated guess. A faster idea is to use QueryPerformanceCounter each
time, or save a QueryPerformanceCounter as a seed. MS itself uses tick
counts (GetTickCount makes no calls, just polls a global/static updated
by the kernel on every context switch) or QueryPerformanceCounter as
seeds for RtlRandom and RtlRandomEx. Also see
http​://code.google.com/searchframe#S3vzerue4i0/trunk/reactos/lib/sdk/crt/startup/gs_support.c&q=__security_init_cookie%20package​:reactos-mirror\.googlecode\.com&l=50

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2012

From @wchristian

On Wed Nov 28 00​:15​:00 2012, bulk88 wrote​:

Why not call the CRT's rand twice or thrice, once for low 15 bits, 2nd
for high 15 bits, and 3rd for remaining 2?

That sounds like a very reasonable solution. Can you maybe implement a
very small c program to generate a million numbers like that and dump
them to STDOUT to check how many collisions result from that algorithm?

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2012

From @demerphq

On 28 November 2012 14​:43, Christian Walde via RT
<perlbug-followup@​perl.org> wrote​:

On Wed Nov 28 00​:15​:00 2012, bulk88 wrote​:

Why not call the CRT's rand twice or thrice, once for low 15 bits, 2nd
for high 15 bits, and 3rd for remaining 2?

That sounds like a very reasonable solution. Can you maybe implement a
very small c program to generate a million numbers like that and dump
them to STDOUT to check how many collisions result from that algorithm?

I am just curious why would that be preferable to just coding your own
longer period LCG?

Afaik they amount to a handful of lines of C.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2012

From @wchristian

On Wed Nov 28 00​:15​:00 2012, bulk88 wrote​:

Why not call the CRT's rand twice or thrice, once for low 15 bits, 2nd
for high 15 bits, and 3rd for remaining 2?

Alright, i talked this through on #p5p and here's the summary as i
understood it​:

First off, the offending property of the windows RNG is granularity in
this case. In this case the granularity is a maximum of 15 bits, which
provides a number of unique results that is far below even a modest sample
size.

Further, in Perl the case is that the random bits gotten from the system
are stuffed into a double float, bounded as [0,1[. This further reduces
the actual number of bits used from the RNG, as such a float can only
contain 53 bits.

On linux, drand48 is used, which provides 48 bits of entropy.

demerphq suggested that it might be possible to select an RNG that could
be implemented for Perl in C, and then be used for both Linux and Windows.
Since the granularity of the current linux generator is below the
granularity that a double can provide, this seems to be a viable path.
However i think this is something that should be carefully considered by
people with the appropiate amount of knowledge and experience, which will
take some time and thus might unnecessarily delay a resolution for
windows. As such i think this should definitely be considered in a
separate ticket.

To the issue at hand, granularity on windows, a solution that seems useful
and provides appropiate granularity would be this​: https​://
gist.github.com/956faeafb71b2ac735aa

I am unsure if it could be extended to provide 53 bits of entropy in a
double even on 32 bit systems and how it would be patched into Perl as it
is. bulk88, i've been told by demerphq that you have the chops and the
platform for this. Could you please look into this?

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2012

From @craigberry

On Wed, Nov 28, 2012 at 7​:51 AM, demerphq <demerphq@​gmail.com> wrote​:

On 28 November 2012 14​:43, Christian Walde via RT
<perlbug-followup@​perl.org> wrote​:

On Wed Nov 28 00​:15​:00 2012, bulk88 wrote​:

Why not call the CRT's rand twice or thrice, once for low 15 bits, 2nd
for high 15 bits, and 3rd for remaining 2?

That sounds like a very reasonable solution. Can you maybe implement a
very small c program to generate a million numbers like that and dump
them to STDOUT to check how many collisions result from that algorithm?

I am just curious why would that be preferable to just coding your own
longer period LCG?

Afaik they amount to a handful of lines of C.

The FreeBSD implementation of drand48() is indeed short and sweet even
if you follow the links a couple of levels deep​:

<http​://fxr.watson.org/fxr/source/gen/drand48.c?v=FREEBSD-LIBC;im=bigexcerpts>

It might just work verbatim on Windows.

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2012

From @kmx

On 28.11.2012 17​:11, Craig A. Berry wrote​:

On Wed, Nov 28, 2012 at 7​:51 AM, demerphq <demerphq@​gmail.com> wrote​:

On 28 November 2012 14​:43, Christian Walde via RT
<perlbug-followup@​perl.org> wrote​:

On Wed Nov 28 00​:15​:00 2012, bulk88 wrote​:

Why not call the CRT's rand twice or thrice, once for low 15 bits, 2nd
for high 15 bits, and 3rd for remaining 2?
That sounds like a very reasonable solution. Can you maybe implement a
very small c program to generate a million numbers like that and dump
them to STDOUT to check how many collisions result from that algorithm?
I am just curious why would that be preferable to just coding your own
longer period LCG?

Afaik they amount to a handful of lines of C.
The FreeBSD implementation of drand48() is indeed short and sweet even
if you follow the links a couple of levels deep​:

<http​://fxr.watson.org/fxr/source/gen/drand48.c?v=FREEBSD-LIBC;im=bigexcerpts>

It might just work verbatim on Windows.

Another candidate (long period, good speed, good randomness) that can be
quite easy to implement is MT19937
https://en.wikipedia.org/wiki/Mersenne_twister

The actual implementation (approx. 100 lines of code) can look like this​:
https://metacpan.org/source/FANGLY/Math-Random-MT-1.16/_mt.c

--
kmx

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2012

From @bulk88

On Wed Nov 28 05​:43​:55 2012, Mithaldu wrote​:

On Wed Nov 28 00​:15​:00 2012, bulk88 wrote​:

Why not call the CRT's rand twice or thrice, once for low 15 bits, 2nd
for high 15 bits, and 3rd for remaining 2?

That sounds like a very reasonable solution. Can you maybe implement a
very small c program to generate a million numbers like that and dump
them to STDOUT to check how many collisions result from that algorithm?

I am going to try to fix this by spreading the bits of whatever rand a
perl is using across the integer bits of a NV (usually 53 bits for a 64
bit double). I plan to test it as XSUBs first and I will post those here.
--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2012

From @paulg1973

FWIW, the C-1990 and C-1999 standards define the rand() function as follows (relevant language extracted)​:

"The rand function computes a sequence of pseudo-random integers in the range 0 to RAND_MAX. ... The value of the RAND_MAX shall be at least 32767."

The Stratus OpenVOS implementation of rand() also limits itself to a RAND_MAX of 32767; I suspect this is due to a desire to maintain compatibility with legacy C programs. Once these limits are defined and widely used, it is impossible to change them without breaking working code.

PG

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2012

From @hvds

"Christian Walde via RT" <perlbug-followup@​perl.org> wrote​:
:To the issue at hand, granularity on windows, a solution that seems useful
:and provides appropiate granularity would be this​: https​://
:gist.github.com/956faeafb71b2ac735aa

If the RNG has a period of 2^15, I believe this solution will have
the same period. (If the RNG had a nearby period that happened to be
a multiple of 3, I believe this solution would have a period only
a third as long.)

Hugo

@p5pRT
Copy link
Author

p5pRT commented Nov 28, 2012

From @tonycoz

On Wed, Nov 28, 2012 at 12​:54​:36PM -0500, Green, Paul wrote​:

FWIW, the C-1990 and C-1999 standards define the rand() function as follows (relevant language extracted)​:

"The rand function computes a sequence of pseudo-random integers in the range 0 to RAND_MAX. ... The value of the RAND_MAX shall be at least 32767."

The Stratus OpenVOS implementation of rand() also limits itself to a RAND_MAX of 32767; I suspect this is due to a desire to maintain compatibility with legacy C programs. Once these limits are defined and widely used, it is impossible to change them without breaking working code.

That doesn't prevent the implementation storing more than 15 bits of
entropy.

It could simply return the lower 15 bits of the result from a 32 or
larger LCRNG implementation, as the simplest example.

Tony

@p5pRT
Copy link
Author

p5pRT commented Nov 29, 2012

From BitCard@ResonatorSoft.org

On Wed Nov 28 09​:55​:18 2012, paulg wrote​:

FWIW, the C-1990 and C-1999 standards define the rand() function as
follows (relevant language extracted)​:

"The rand function
computes a sequence of pseudo-random integers in the range 0 to
RAND_MAX. ... The value of the RAND_MAX shall be at least 32767."
The Stratus OpenVOS implementation of rand() also limits itself to
a RAND_MAX of 32767; I suspect this is due to a desire to maintain
compatibility with legacy C programs. Once these limits are
defined and widely used, it is impossible to change them without
breaking working code.

Perl isn't C. We document that rand returns "a random fractional number
greater than or equal to 0 and less than the value of EXPR". While bits
of entropy isn't documented here, I think we can all agree that 15 bits
is too low.

I like bulk77's solution. It's fast and portably achieves the maximum
entropy based on IV length. Any crypto-security issues or special algorithms can be covered in other modules.

@p5pRT
Copy link
Author

p5pRT commented Nov 29, 2012

From @ap

* bulk88 via RT <perlbug-followup@​perl.org> [2012-11-28 09​:20]​:

Why not call the CRT's rand twice or thrice, once for low 15 bits, 2nd
for high 15 bits, and 3rd for remaining 2?

That doesn’t increase the entropy available, it just draws from the pool
faster. I don’t have my randomness down well enough to reason it through
with the necessary rigour but I’m pretty sure that at best that approach
does nothing to increase the quality of the random numbers and likely it
will decrease it.

Don’t.

Randomness is a treacherous sea – easy to get it wrong, hard to notice
when you do, and with far-reaching consequences. (Debian patched some
random number generator and caused half the world to have to mint new
SSH keys a few years down the line.)

Find a syscall that draws from a deeper pool or put in some other known
algorithm with a greater amount of hidden state or really just about any
other approach except this one.

Or just leave it as it is. If it’s bad, just let it look bad. Being bad
is not a problem (absent promises about quality – and perl makes none)
but looking better than it is would be.

The documentation already covers everything it needs to, so nothing to
be done there either.

Regards,
--
Aristotle Pagaltzis // <http​://plasmasturm.org/>

@p5pRT
Copy link
Author

p5pRT commented Nov 29, 2012

From @ap

* Aristotle Pagaltzis <pagaltzis@​gmx.de> [2012-11-29 03​:01]​:

Randomness is a treacherous sea – easy to get it wrong, hard to notice
when you do, and with far-reaching consequences. (Debian patched some
random number generator and caused half the world to have to mint new
SSH keys a few years down the line.)

And just as I send this mail, I notice that last week’s LWN has come out
from under the paywall​:

  LCE​: Don’t play dice with random numbers
  https://lwn.net/Articles/525459/

Regards,
--
Aristotle Pagaltzis // <http​://plasmasturm.org/>

@p5pRT
Copy link
Author

p5pRT commented Nov 29, 2012

From @doy

On Thu, Nov 29, 2012 at 03​:01​:00AM +0100, Aristotle Pagaltzis wrote​:

* bulk88 via RT <perlbug-followup@​perl.org> [2012-11-28 09​:20]​:

Why not call the CRT's rand twice or thrice, once for low 15 bits, 2nd
for high 15 bits, and 3rd for remaining 2?

That doesn’t increase the entropy available, it just draws from the pool
faster. I don’t have my randomness down well enough to reason it through
with the necessary rigour but I’m pretty sure that at best that approach
does nothing to increase the quality of the random numbers and likely it
will decrease it.

Don’t.

Randomness is a treacherous sea – easy to get it wrong, hard to notice
when you do, and with far-reaching consequences. (Debian patched some
random number generator and caused half the world to have to mint new
SSH keys a few years down the line.)

Find a syscall that draws from a deeper pool or put in some other known
algorithm with a greater amount of hidden state or really just about any
other approach except this one.

Or just leave it as it is. If it’s bad, just let it look bad. Being bad
is not a problem (absent promises about quality – and perl makes none)
but looking better than it is would be.

The documentation already covers everything it needs to, so nothing to
be done there either.

As was pointed out on IRC, there are actually two orthogonal concerns
here - how long until the sequence of random numbers repeats, and how
many distinct numbers are able to be generated. The proposed solution
here will increase the second while potentially (although not
necessarily) decreasing the first. This isn't necessarily a bad
tradeoff, depending on what the period actually is (it could easily be
far greater than the number of distinct numbers that can be generated,
if the generator keeps hidden internal state). There's nothing
inherently problematic about this idea, as long as you're aware that
it's only going to increase the potential range of numbers generated,
not increase the randomness itself.

That said, I do tend to agree with Yves here - if we're actually
concerned about the quality of the random numbers that are avaialble,
good rngs are pretty trivial to implement (or steal), so we may as well
just do that if want to go down this road.

-doy

@p5pRT
Copy link
Author

p5pRT commented Nov 29, 2012

From @bulk88

On Wed Nov 28 09​:41​:59 2012, bulk88 wrote​:

On Wed Nov 28 05​:43​:55 2012, Mithaldu wrote​:

On Wed Nov 28 00​:15​:00 2012, bulk88 wrote​:

Why not call the CRT's rand twice or thrice, once for low 15 bits, 2nd
for high 15 bits, and 3rd for remaining 2?

That sounds like a very reasonable solution. Can you maybe implement a
very small c program to generate a million numbers like that and dump
them to STDOUT to check how many collisions result from that algorithm?

I am going to try to fix this by spreading the bits of whatever rand a
perl is using across the integer bits of a NV (usually 53 bits for a 64
bit double). I plan to test it as XSUBs first and I will post those here.

Windows only right now.
______________________________________________________--

NV
RunRand(...)
PREINIT​:
  LARGE_INTEGER my_beg;
  LARGE_INTEGER my_end;
  LARGE_INTEGER my_freq;
  NV value;
  int io;
CODE​:
  if (!PL_srand_called) {
  (void)seedDrand01((Rand_seed_t)seed());
  PL_srand_called = TRUE;
  }
  RETVAL = 0.0;
  QueryPerformanceFrequency(&my_freq);
 
  QueryPerformanceCounter(&my_beg);
  for(io=0; io < 10000000; io++)
  {
  int i;
  NV randnv = 0.0;
  const int nvofbits = NV_OVERFLOW_BITS;
  const NV overflowat = NV_OVERFLOWS_INTEGERS_AT;
  NV mulby;
  value = 1.0;
  for(i=0; i < nvofbits; i += RANDBITS){
  NV randraw = rand();
  if (nvofbits - i < RANDBITS) {
  /* In the last loop iteration, we have
  to cut off the high bits, so we don't overflow the
mantissa
  */
  /* scalb is slower than pow */
  NV mask = Perl_pow(2, nvofbits - i > RANDBITS ?
RANDBITS : nvofbits - i) - 1;
  randraw = Perl_fmod(randraw, mask); /* & the bits */
 
  }
  randraw *= Perl_pow(2, i); /* << the bits */
  randnv += randraw; /* | the bits */
  }
  mulby = (randnv / overflowat); /* >> so randnv is between
0.0 and 1.0 */
  value *= mulby;
  RETVAL += value;
  }
  QueryPerformanceCounter(&my_end);
  printf("new time=%f, opt=" OPTIMIZE "\n",
((double)(my_end.QuadPart-my_beg.QuadPart))/(double)my_freq.QuadPart);
 
  QueryPerformanceCounter(&my_beg);
  for(io=0; io < 10000000; io++){
  value = 1.0;
  value *= Drand01();
  RETVAL += value;
  }
  QueryPerformanceCounter(&my_end);
  printf("old time=%f, opt=" OPTIMIZE "\n",
((double)(my_end.QuadPart-my_beg.QuadPart))/(double)my_freq.QuadPart);
OUTPUT​:
  RETVAL
_____________________________________________________

new time=6.786747, opt= -O1 -G7 -GL -Oi -Og
old time=0.167446, opt= -O1 -G7 -GL -Oi -Og
_____________________________________________________
That is 42 times slower than the previous implementation. I already
moved the bit masking into a conditional, that shaved off 4 seconds.
scalb made things .2 to .5 second worse. A hand written pow loop in a
function took 8 seconds instead of the 6. A header file is included that
RunRand requires. nvoverflowbits.h was created using a script, but
Visual C had a "parser stack overflow" (C1026) when upto 256 bits where
in the conditional tree. I guess I have to somehow cache the Perl_pow
results in global statics and calculate them once per process startup.
The whole loop can be unrolled actually, but it wouldn't be portable if
it is unrolled by hand.

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Nov 29, 2012

From @bulk88

nvoverflowbits.h

@p5pRT
Copy link
Author

p5pRT commented Nov 29, 2012

From @bulk88

On Wed Nov 28 23​:13​:32 2012, bulk88 wrote​:

I guess I have to somehow cache the Perl_pow
results in global statics and calculate them once per process startup.
The whole loop can be unrolled actually, but it wouldn't be portable if
it is unrolled by hand.

On the collisions test posted by Brendan Byrd, the new rand returned 0.

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Aug 9, 2013

From @tonycoz

On Thu Aug 08 05​:10​:52 2013, craig.a.berry@​gmail.com wrote​:

On Thu, Aug 8, 2013 at 2​:03 AM, Tony Cook via RT
<perlbug-followup@​perl.org> wrote​:

My original check used HAS_QUAD, and I was surprised once I ran it on a
32-bit OS (where the compiler has 64-bit integers) that it continued to
use the original portable version.

It turns out that perl.h undefs HAS_QUAD, but there's no explanation of
why (assuming I'm not mis-reading the code.)

Is it the intent that we never uses 64-bit types on 32-bit platforms?

Not sure why HAS_QUAD gets undef'd but perhaps checking for Quad_t
instead would do the trick. On the other hand ISTR that Win32
implements 64-bit ints in software (at least on some systems), so
they'll be very slow.

Both GCC and MSVC implement 64-bit integers in software on 32-bit
platforms, the main difference (in this case) is that GCC inlines
multiplications while MSVC calls out to a fairly simple library function
(written in assembler) to do the job.

For 64-bit platforms the code generated is roughly* equivalent between
MSVC and GCC.

It turned out both changes failed to build on MSVC due to an excess
semi-colon.

Tony

* if you close one eye and squint

@p5pRT
Copy link
Author

p5pRT commented Aug 9, 2013

From @demerphq

On 19 July 2013 09​:59, Tony Cook via RT <perlbug-followup@​perl.org> wrote​:

On Tue Dec 18 13​:55​:44 2012, demerphq wrote​:

Oh, i deleted and recreated a rebased smoke-me/builtin_rng so be
careful how you update. Do a fetch and reset --hard.

The list seems to have lost interest in this ticket, and I don't recall
any other fixes being pushed for it.

One problem I see with the smoke-me/builtin_rng branch is that WELLRNGa
code is GPL which I believe is not suitable for inclusion in perl.

I've rebased smoke-me/builtin_rng and pushed to tonyc/builtin_rng.

It was on my "bring up later" todo list, but I am fine that you have
picked it up and are getting it done. Very pleased actually.

And I am fine with you making it just use the drand48 implementation.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Aug 22, 2013

From @tonycoz

On Thu Aug 08 00​:03​:28 2013, tonyc wrote​:

On Thu Jul 25 00​:00​:27 2013, tonyc wrote​:

c) use our drand48() always, don't bother setting $Config{drand01} etc.

I've attached two implementations.

The first is as I said above - a purely private to perl implementation.

But from looking at the perl sources, List-Util uses perl's
seedDrand01() and Drand01(), from from checking CPAN, many CPAN modules
also use them.

So I've prepared an alternate patch that replaces the macros so that
modules will use the new random number implementation.

One problem with not updating $Config{randbits} in particular is that
code that sensibly looks at that value to check is rand() is sane or not
will be relying on incorrect data.

So I'm wondering whether Configure should be updated to set the new
values for 5.19 and later (I believe Configure is meant to be roughly
back-copyable.), or not.

If Configure is updated, configure.com will also need to be updated.

Tony

@p5pRT
Copy link
Author

p5pRT commented Aug 23, 2013

From @craigberry

On Thu, Aug 22, 2013 at 6​:24 PM, Tony Cook via RT
<perlbug-followup@​perl.org> wrote​:

On Thu Aug 08 00​:03​:28 2013, tonyc wrote​:

On Thu Jul 25 00​:00​:27 2013, tonyc wrote​:

c) use our drand48() always, don't bother setting $Config{drand01} etc.

I've attached two implementations.

The first is as I said above - a purely private to perl implementation.

But from looking at the perl sources, List-Util uses perl's
seedDrand01() and Drand01(), from from checking CPAN, many CPAN modules
also use them.

So I've prepared an alternate patch that replaces the macros so that
modules will use the new random number implementation.

One problem with not updating $Config{randbits} in particular is that
code that sensibly looks at that value to check is rand() is sane or not
will be relying on incorrect data.

So I'm wondering whether Configure should be updated to set the new
values for 5.19 and later (I believe Configure is meant to be roughly
back-copyable.), or not.

If Configure is updated, configure.com will also need to be updated.

The current test for randbits in configure.com will return 48 on all
VMS systems 7.0 and later, i.e., the last eighteen years or so, which
conveniently includes everything not already explicitly desupported in
Perl. But yes, if we know the answer because we no longer use the
system function, we can remove the test and just hardwire it to 48.
Ditto for win32/config.* and config_H.*.

@p5pRT
Copy link
Author

p5pRT commented Aug 23, 2013

From @Tux

On Thu, 22 Aug 2013 16​:24​:01 -0700, "Tony Cook via RT"
<perlbug-followup@​perl.org> wrote​:

On Thu Aug 08 00​:03​:28 2013, tonyc wrote​:

On Thu Jul 25 00​:00​:27 2013, tonyc wrote​:

c) use our drand48() always, don't bother setting $Config{drand01} etc.

I've attached two implementations.

The first is as I said above - a purely private to perl implementation.

But from looking at the perl sources, List-Util uses perl's
seedDrand01() and Drand01(), from from checking CPAN, many CPAN modules
also use them.

So I've prepared an alternate patch that replaces the macros so that
modules will use the new random number implementation.

One problem with not updating $Config{randbits} in particular is that
code that sensibly looks at that value to check is rand() is sane or not
will be relying on incorrect data.

So I'm wondering whether Configure should be updated to set the new
values for 5.19 and later (I believe Configure is meant to be roughly
back-copyable.), or not.

No anymore. git helps. Only backportable patches are picked to
maint/older. With git, current Configure belongs to current perl

So yes, I think having Configure in sync would help​:

$ perl -V​:.*rand.*
d_drand48_r='undef';
d_drand48proto='define';
d_random_r='undef';
d_srand48_r='undef';
d_srandom_r='undef';
drand01='drand48()';
drand48_r_proto='0';
randbits='48';
randfunc='drand48';
random_r_proto='0';
randseedtype='long';
srand48_r_proto='0';
srandom_r_proto='0';

If Configure is updated, configure.com will also need to be updated.

--
H.Merijn Brand http​://tux.nl Perl Monger http​://amsterdam.pm.org/
using perl5.00307 .. 5.19 porting perl5 on HP-UX, AIX, and openSUSE
http​://mirrors.develooper.com/hpux/ http​://www.test-smoke.org/
http​://qa.perl.org http​://www.goldmark.org/jeff/stupid-disclaimers/

@p5pRT
Copy link
Author

p5pRT commented Sep 4, 2013

From @tonycoz

On Thu Aug 22 23​:39​:36 2013, hmbrand wrote​:

On Thu, 22 Aug 2013 16​:24​:01 -0700, "Tony Cook via RT"
<perlbug-followup@​perl.org> wrote​:

On Thu Aug 08 00​:03​:28 2013, tonyc wrote​:

On Thu Jul 25 00​:00​:27 2013, tonyc wrote​:

c) use our drand48() always, don't bother setting
$Config{drand01} etc.

I've attached two implementations.

The first is as I said above - a purely private to perl
implementation.

But from looking at the perl sources, List-Util uses perl's
seedDrand01() and Drand01(), from from checking CPAN, many CPAN
modules
also use them.

So I've prepared an alternate patch that replaces the macros so
that
modules will use the new random number implementation.

One problem with not updating $Config{randbits} in particular is
that
code that sensibly looks at that value to check is rand() is sane or
not
will be relying on incorrect data.

So I'm wondering whether Configure should be updated to set the new
values for 5.19 and later (I believe Configure is meant to be
roughly
back-copyable.), or not.

No anymore. git helps. Only backportable patches are picked to
maint/older. With git, current Configure belongs to current perl

So yes, I think having Configure in sync would help​:

$ perl -V​:.*rand.*
d_drand48_r='undef';
d_drand48proto='define';
d_random_r='undef';
d_srand48_r='undef';
d_srandom_r='undef';
drand01='drand48()';
drand48_r_proto='0';
randbits='48';
randfunc='drand48';
random_r_proto='0';
randseedtype='long';
srand48_r_proto='0';
srandom_r_proto='0';

If Configure is updated, configure.com will also need to be updated.

tonyc/drandpublic now includes a Configure change to always use the new
built-in drand() implementation.

I'm not sure whether we should support continuing to use the older
alternatives.

Tony

@p5pRT
Copy link
Author

p5pRT commented Sep 6, 2013

From @nwc10

On Thu, Aug 08, 2013 at 12​:03​:30AM -0700, Tony Cook via RT wrote​:

So I've prepared an alternate patch that replaces the macros so that
modules will use the new random number implementation.

In terms of implementation - the freebsd implementation is nice and
portable for 32-bit systems, but doesn't take advantage of​:

a) native 64-bit systems

b) 64-bit types on 32-bit systems

Each of the patches above includes a 64-bit alternative implementation
of the same algorithm.

My original check used HAS_QUAD, and I was surprised once I ran it on a
32-bit OS (where the compiler has 64-bit integers) that it continued to
use the original portable version.

It turns out that perl.h undefs HAS_QUAD, but there's no explanation of
why (assuming I'm not mis-reading the code.)

Is it the intent that we never uses 64-bit types on 32-bit platforms?

I don't know why.

It dates from this commit

commit de1c261
Author​: Jarkko Hietaniemi <jhi@​iki.fi>
Date​: Sat Oct 30 12​:41​:50 1999 +0000

  Add HAS_QUAD ($Config{d_quad}); use it.
 
  p4raw-id​: //depot/cfgperl@​4497

which adds the #undef into

# if IVSIZE == 8
# define IV_IS_QUAD
# define UV_IS_QUAD
# ifndef HAS_QUAD
# define HAS_QUAD
# endif
# else
# undef IV_IS_QUAD
# undef UV_IS_QUAD
# undef HAS_QUAD
# endif

I think that the uses of HAS_QUAD in the core to conditionally compile code
are incorrect, in that both should actually be UV_IS_QUAD or IVSIZE == 8.

Of the 26 references to it on CPAN outside of ppport.h, 6 are in the core
or copies of core config files, so that's (at most) only 20 distributions
which might break if we changed this​:

http​://grep.cpan.me/?q=%5CbHAS_QUAD%5Cb+-file%3Appport.h

I don't think that the current perl.h is correct (or useful) -
we should change perl.h so that HAS_QUAD does what it's *documented* to do -
describe the presence of a quad type. And test the relevant CPAN distributions
and if necessary patch them to be happy.

(I'll finish this e-mail, then create a ticket, then reference it from here)

On Tue, Sep 03, 2013 at 06​:33​:24PM -0700, Tony Cook via RT wrote​:

On Thu Aug 22 23​:39​:36 2013, hmbrand wrote​:

On Thu, 22 Aug 2013 16​:24​:01 -0700, "Tony Cook via RT"

So I'm wondering whether Configure should be updated to set the new
values for 5.19 and later (I believe Configure is meant to be
roughly
back-copyable.), or not.

No anymore. git helps. Only backportable patches are picked to
maint/older. With git, current Configure belongs to current perl

So yes, I think having Configure in sync would help​:

$ perl -V​:.*rand.*
d_drand48_r='undef';
d_drand48proto='define';
d_random_r='undef';
d_srand48_r='undef';
d_srandom_r='undef';
drand01='drand48()';
drand48_r_proto='0';
randbits='48';
randfunc='drand48';
random_r_proto='0';
randseedtype='long';
srand48_r_proto='0';
srandom_r_proto='0';

seed|rand seems to be a better search pattern.

If Configure is updated, configure.com will also need to be updated.

tonyc/drandpublic now includes a Configure change to always use the new
built-in drand() implementation.

I'm not sure whether we should support continuing to use the older
alternatives.

I think that we should drop them. Of all the random number related config.sh
entries and config.h defines​:

$ perl -wlne '++$h{$1} if /^(.*(rand|seed).*)=/; END {print "http​://grep.cpan.me/?q=\\b(" . join("|", sort keys %h) . ")\\b"}' config.shhttp​://grep.cpan.me/?q=\b(d_drand48_r|d_drand48proto|d_random_r|d_srand48_r|d_srandom_r|drand01|drand48_r_proto|randbits|randfunc|random_r_proto|randseedtype|seedfunc|srand48_r_proto|srandom_r_proto)\b

$ perl -wlne 'next unless /^#.*(seed|rand)/; if (/^#define ([a-zA-Z_0-9]+)/) {++$h{$1}} elsif (/^#\$\S+\s+(\S+)/) {++$h{$1}} else {die $_}; END {print "http​://grep.cpan.me/?q=\\b(" . join("|", sort keys %h) . ")\\b"}' config_h.SH
http​://grep.cpan.me/?q=\b(DRAND48_R_PROTO|Drand01|HAS_DRAND48_PROTO|HAS_DRAND48_R|HAS_RANDOM_R|HAS_SRAND48_R|HAS_SRANDOM_R|RANDBITS|RANDOM_R_PROTO|Rand_seed_t|SRAND48_R_PROTO|SRANDOM_R_PROTO|seedDrand01)\b

Aside from one module from Ton Hospel, the only C macros which are used are
RANDBITS, Drand01(), seedDrand01() and Rand_seed_t.

That use is in https://metacpan.org/release/Graph-Layout-Aesthetic
in this code​:

  /* Needed on systems that use drand48 for Drand01 but have no prototype */
  #ifndef HAS_DRAND48_PROTO
  extern double drand48(void);
  #endif

it's not going to break if HAS_DRAND48_PROTO goes away (unless the system
is severely non-POSIX) and we can offer a patch anyway.

All the (other) config.sh values can safely become undef without causing
any code to notice, as long as these 5 remain valid​:

randfunc=freebsd_drand48_generate_double
drand01="freebsd_drand48_generate_double()"
seedfunc="freebsd_drand48_init"
randbits=48
randseedtype=U32

We can remove all the probing code from Configure, and the reentr.[hc] code
that deals with *_r variants, which is (initially) this​:

Configure | 200 ++-----------------------------------------------------
reentr.c | 18 -----
reentr.h | 145 ++++++++++------------------------------
regen/reentr.pl | 45 +------------
4 files changed, 43 insertions(+), 365 deletions(-)

[all tests pass]

but probably can be a lot better as we can delete 9 lines from every potted
config.sh entry for

  d_drand48_r d_drand48proto d_random_r d_srand48_r d_srandom_r
  drand48_r_proto random_r_proto srand48_r_proto srandom_r_proto

along with Glossary, config_h.SH and maybe more.

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented Sep 6, 2013

From @nwc10

Inline Patch
diff --git a/Configure b/Configure
index e1e9241..e8a0d9a 100755
--- a/Configure
+++ b/Configure
@@ -418,9 +418,6 @@ d_dlopen=''
 d_dlsymun=''
 d_dosuid=''
 d_suidsafe=''
-d_drand48_r=''
-drand48_r_proto=''
-d_drand48proto=''
 d_dup2=''
 d_eaccess=''
 d_endgrent=''
@@ -640,8 +637,6 @@ d_pthread_yield=''
 d_sched_yield=''
 sched_yield=''
 d_qgcvt=''
-d_random_r=''
-random_r_proto=''
 d_readdir64_r=''
 readdir64_r_proto=''
 d_readdir=''
@@ -746,10 +741,6 @@ d_socklen_t=''
 d_socks5_init=''
 d_sprintf_returns_strlen=''
 d_sqrtl=''
-d_srand48_r=''
-srand48_r_proto=''
-d_srandom_r=''
-srandom_r_proto=''
 d_sresgproto=''
 d_sresuproto=''
 d_statblks=''
@@ -12175,52 +12166,6 @@ $rm -f fred fred.* dyna.$dlext dyna.* tmp-dyna.*
 set d_dlsymun
 eval $setvar
 
-: see if drand48_r exists
-set drand48_r d_drand48_r
-eval $inlibc
-case "$d_drand48_r" in
-"$define")
-	hdrs="$i_systypes sys/types.h define stdio.h $i_stdlib stdlib.h"
-	case "$d_drand48_r_proto:$usethreads" in
-	":define")	d_drand48_r_proto=define
-		set d_drand48_r_proto drand48_r $hdrs
-		eval $hasproto ;;
-	*)	;;
-	esac
-	case "$d_drand48_r_proto" in
-	define)
-	case "$drand48_r_proto" in
-	''|0) try='int drand48_r(struct drand48_data*, double*);'
-	./protochk "$extern_C $try" $hdrs && drand48_r_proto=I_ST ;;
-	esac
-	case "$drand48_r_proto" in
-	''|0)	d_drand48_r=undef
- 	        drand48_r_proto=0
-		echo "Disabling drand48_r, cannot determine prototype." >&4 ;;
-	* )	case "$drand48_r_proto" in
-		REENTRANT_PROTO*) ;;
-		*) drand48_r_proto="REENTRANT_PROTO_$drand48_r_proto" ;;
-		esac
-		echo "Prototype: $try" ;;
-	esac
-	;;
-	*)	case "$usethreads" in
-		define) echo "drand48_r has no prototype, not using it." >&4 ;;
-		esac
-		d_drand48_r=undef
-		drand48_r_proto=0
-		;;
-	esac
-	;;
-*)	drand48_r_proto=0
-	;;
-esac
-
-: see if prototype for drand48 is available
-echo " "
-set d_drand48proto drand48 $i_stdlib stdlib.h $i_unistd unistd.h
-eval $hasproto
-
 : see if dup2 exists
 set dup2 d_dup2
 eval $inlibc
@@ -16483,55 +16428,6 @@ case "$sched_yield" in
 esac
 $rm_try
 
-: see if random_r exists
-set random_r d_random_r
-eval $inlibc
-case "$d_random_r" in
-"$define")
-	hdrs="$i_systypes sys/types.h define stdio.h $i_stdlib stdlib.h"
-	case "$d_random_r_proto:$usethreads" in
-	":define")	d_random_r_proto=define
-		set d_random_r_proto random_r $hdrs
-		eval $hasproto ;;
-	*)	;;
-	esac
-	case "$d_random_r_proto" in
-	define)
-	case "$random_r_proto" in
-	''|0) try='int random_r(int*, struct random_data*);'
-	./protochk "$extern_C $try" $hdrs && random_r_proto=I_iS ;;
-	esac
-	case "$random_r_proto" in
-	''|0) try='int random_r(long*, struct random_data*);'
-	./protochk "$extern_C $try" $hdrs && random_r_proto=I_lS ;;
-	esac
-	case "$random_r_proto" in
-	''|0) try='int random_r(struct random_data*, int32_t*);'
-	./protochk "$extern_C $try" $hdrs && random_r_proto=I_St ;;
-	esac
-	case "$random_r_proto" in
-	''|0)	d_random_r=undef
- 	        random_r_proto=0
-		echo "Disabling random_r, cannot determine prototype." >&4 ;;
-	* )	case "$random_r_proto" in
-		REENTRANT_PROTO*) ;;
-		*) random_r_proto="REENTRANT_PROTO_$random_r_proto" ;;
-		esac
-		echo "Prototype: $try" ;;
-	esac
-	;;
-	*)	case "$usethreads" in
-		define) echo "random_r has no prototype, not using it." >&4 ;;
-		esac
-		d_random_r=undef
-		random_r_proto=0
-		;;
-	esac
-	;;
-*)	random_r_proto=0
-	;;
-esac
-
 : see if readdir and friends exist
 set readdir d_readdir
 eval $inlibc
@@ -17954,88 +17850,6 @@ else
 fi
 $rm_try
 
-: see if srand48_r exists
-set srand48_r d_srand48_r
-eval $inlibc
-case "$d_srand48_r" in
-"$define")
-	hdrs="$i_systypes sys/types.h define stdio.h $i_stdlib stdlib.h"
-	case "$d_srand48_r_proto:$usethreads" in
-	":define")	d_srand48_r_proto=define
-		set d_srand48_r_proto srand48_r $hdrs
-		eval $hasproto ;;
-	*)	;;
-	esac
-	case "$d_srand48_r_proto" in
-	define)
-	case "$srand48_r_proto" in
-	''|0) try='int srand48_r(long, struct drand48_data*);'
-	./protochk "$extern_C $try" $hdrs && srand48_r_proto=I_LS ;;
-	esac
-	case "$srand48_r_proto" in
-	''|0)	d_srand48_r=undef
- 	        srand48_r_proto=0
-		echo "Disabling srand48_r, cannot determine prototype." >&4 ;;
-	* )	case "$srand48_r_proto" in
-		REENTRANT_PROTO*) ;;
-		*) srand48_r_proto="REENTRANT_PROTO_$srand48_r_proto" ;;
-		esac
-		echo "Prototype: $try" ;;
-	esac
-	;;
-	*)	case "$usethreads" in
-		define) echo "srand48_r has no prototype, not using it." >&4 ;;
-		esac
-		d_srand48_r=undef
-		srand48_r_proto=0
-		;;
-	esac
-	;;
-*)	srand48_r_proto=0
-	;;
-esac
-
-: see if srandom_r exists
-set srandom_r d_srandom_r
-eval $inlibc
-case "$d_srandom_r" in
-"$define")
-	hdrs="$i_systypes sys/types.h define stdio.h $i_stdlib stdlib.h"
-	case "$d_srandom_r_proto:$usethreads" in
-	":define")	d_srandom_r_proto=define
-		set d_srandom_r_proto srandom_r $hdrs
-		eval $hasproto ;;
-	*)	;;
-	esac
-	case "$d_srandom_r_proto" in
-	define)
-	case "$srandom_r_proto" in
-	''|0) try='int srandom_r(unsigned int, struct random_data*);'
-	./protochk "$extern_C $try" $hdrs && srandom_r_proto=I_TS ;;
-	esac
-	case "$srandom_r_proto" in
-	''|0)	d_srandom_r=undef
- 	        srandom_r_proto=0
-		echo "Disabling srandom_r, cannot determine prototype." >&4 ;;
-	* )	case "$srandom_r_proto" in
-		REENTRANT_PROTO*) ;;
-		*) srandom_r_proto="REENTRANT_PROTO_$srandom_r_proto" ;;
-		esac
-		echo "Prototype: $try" ;;
-	esac
-	;;
-	*)	case "$usethreads" in
-		define) echo "srandom_r has no prototype, not using it." >&4 ;;
-		esac
-		d_srandom_r=undef
-		srandom_r_proto=0
-		;;
-	esac
-	;;
-*)	srandom_r_proto=0
-	;;
-esac
-
 : see if prototype for setresgid is available
 echo " "
 set d_sresgproto setresgid $i_unistd unistd.h
@@ -22943,8 +22757,8 @@ d_dlerror='$d_dlerror'
 d_dlopen='$d_dlopen'
 d_dlsymun='$d_dlsymun'
 d_dosuid='$d_dosuid'
-d_drand48_r='$d_drand48_r'
-d_drand48proto='$d_drand48proto'
+d_drand48_r='undef'
+d_drand48proto='undef'
 d_dup2='$d_dup2'
 d_eaccess='$d_eaccess'
 d_endgrent='$d_endgrent'
@@ -23163,7 +22977,7 @@ d_pwpasswd='$d_pwpasswd'
 d_pwquota='$d_pwquota'
 d_qgcvt='$d_qgcvt'
 d_quad='$d_quad'
-d_random_r='$d_random_r'
+d_random_r='undef'
 d_readdir64_r='$d_readdir64_r'
 d_readdir='$d_readdir'
 d_readdir_r='$d_readdir_r'
@@ -23245,8 +23059,8 @@ d_sockpair='$d_sockpair'
 d_socks5_init='$d_socks5_init'
 d_sprintf_returns_strlen='$d_sprintf_returns_strlen'
 d_sqrtl='$d_sqrtl'
-d_srand48_r='$d_srand48_r'
-d_srandom_r='$d_srandom_r'
+d_srand48_r='undef'
+d_srandom_r='undef'
 d_sresgproto='$d_sresgproto'
 d_sresuproto='$d_sresuproto'
 d_statblks='$d_statblks'
@@ -23339,7 +23153,6 @@ dlext='$dlext'
 dlsrc='$dlsrc'
 doublesize='$doublesize'
 drand01='$drand01'
-drand48_r_proto='$drand48_r_proto'
 dtrace='$dtrace'
 dynamic_ext='$dynamic_ext'
 eagain='$eagain'
@@ -23672,7 +23485,6 @@ quadkind='$quadkind'
 quadtype='$quadtype'
 randbits='$randbits'
 randfunc='$randfunc'
-random_r_proto='$random_r_proto'
 randseedtype='$randseedtype'
 ranlib='$ranlib'
 rd_nodata='$rd_nodata'
@@ -23760,8 +23572,6 @@ socksizetype='$socksizetype'
 sort='$sort'
 spackage='$spackage'
 spitshell='$spitshell'
-srand48_r_proto='$srand48_r_proto'
-srandom_r_proto='$srandom_r_proto'
 src='$src'
 ssizetype='$ssizetype'
 st_ino_sign='$st_ino_sign'
diff --git a/reentr.c b/reentr.c
index 31b933c..a5ea192 100644
--- a/reentr.c
+++ b/reentr.c
@@ -40,8 +40,6 @@ Perl_reentrant_size(pTHX) {
 #ifdef HAS_CTIME_R
 	PL_reentrant_buffer->_ctime_size = REENTRANTSMALLSIZE;
 #endif /* HAS_CTIME_R */
-#ifdef HAS_DRAND48_R
-#endif /* HAS_DRAND48_R */
 #ifdef HAS_GETGRNAM_R
 #   if defined(HAS_SYSCONF) && defined(_SC_GETGR_R_SIZE_MAX) && !defined(__GLIBC__)
 	PL_reentrant_buffer->_grent_size = sysconf(_SC_GETGR_R_SIZE_MAX);
@@ -116,8 +114,6 @@ Perl_reentrant_size(pTHX) {
 #       endif
 #   endif 
 #endif /* HAS_GETSPNAM_R */
-#ifdef HAS_RANDOM_R
-#endif /* HAS_RANDOM_R */
 #ifdef HAS_READDIR_R
 	/* This is the size Solaris recommends.
 	 * (though we go static, should use pathconf() instead) */
@@ -131,8 +127,6 @@ Perl_reentrant_size(pTHX) {
 #ifdef HAS_SETLOCALE_R
 	PL_reentrant_buffer->_setlocale_size = REENTRANTSMALLSIZE;
 #endif /* HAS_SETLOCALE_R */
-#ifdef HAS_SRANDOM_R
-#endif /* HAS_SRANDOM_R */
 #ifdef HAS_STRERROR_R
 	PL_reentrant_buffer->_strerror_size = REENTRANTSMALLSIZE;
 #endif /* HAS_STRERROR_R */
@@ -159,8 +153,6 @@ Perl_reentrant_init(pTHX) {
 #ifdef HAS_CTIME_R
 	Newx(PL_reentrant_buffer->_ctime_buffer, PL_reentrant_buffer->_ctime_size, char);
 #endif /* HAS_CTIME_R */
-#ifdef HAS_DRAND48_R
-#endif /* HAS_DRAND48_R */
 #ifdef HAS_GETGRNAM_R
 #   ifdef USE_GRENT_FPTR
 	PL_reentrant_buffer->_grent_fptr = NULL;
@@ -202,8 +194,6 @@ Perl_reentrant_init(pTHX) {
 #   endif
 	Newx(PL_reentrant_buffer->_spent_buffer, PL_reentrant_buffer->_spent_size, char);
 #endif /* HAS_GETSPNAM_R */
-#ifdef HAS_RANDOM_R
-#endif /* HAS_RANDOM_R */
 #ifdef HAS_READDIR_R
 	PL_reentrant_buffer->_readdir_struct = (struct dirent*)safemalloc(PL_reentrant_buffer->_readdir_size);
 #endif /* HAS_READDIR_R */
@@ -213,8 +203,6 @@ Perl_reentrant_init(pTHX) {
 #ifdef HAS_SETLOCALE_R
 	Newx(PL_reentrant_buffer->_setlocale_buffer, PL_reentrant_buffer->_setlocale_size, char);
 #endif /* HAS_SETLOCALE_R */
-#ifdef HAS_SRANDOM_R
-#endif /* HAS_SRANDOM_R */
 #ifdef HAS_STRERROR_R
 	Newx(PL_reentrant_buffer->_strerror_buffer, PL_reentrant_buffer->_strerror_size, char);
 #endif /* HAS_STRERROR_R */
@@ -239,8 +227,6 @@ Perl_reentrant_free(pTHX) {
 #ifdef HAS_CTIME_R
 	Safefree(PL_reentrant_buffer->_ctime_buffer);
 #endif /* HAS_CTIME_R */
-#ifdef HAS_DRAND48_R
-#endif /* HAS_DRAND48_R */
 #ifdef HAS_GETGRNAM_R
 	Safefree(PL_reentrant_buffer->_grent_buffer);
 #endif /* HAS_GETGRNAM_R */
@@ -273,8 +259,6 @@ Perl_reentrant_free(pTHX) {
 #ifdef HAS_GETSPNAM_R
 	Safefree(PL_reentrant_buffer->_spent_buffer);
 #endif /* HAS_GETSPNAM_R */
-#ifdef HAS_RANDOM_R
-#endif /* HAS_RANDOM_R */
 #ifdef HAS_READDIR_R
 	Safefree(PL_reentrant_buffer->_readdir_struct);
 #endif /* HAS_READDIR_R */
@@ -284,8 +268,6 @@ Perl_reentrant_free(pTHX) {
 #ifdef HAS_SETLOCALE_R
 	Safefree(PL_reentrant_buffer->_setlocale_buffer);
 #endif /* HAS_SETLOCALE_R */
-#ifdef HAS_SRANDOM_R
-#endif /* HAS_SRANDOM_R */
 #ifdef HAS_STRERROR_R
 	Safefree(PL_reentrant_buffer->_strerror_buffer);
 #endif /* HAS_STRERROR_R */
diff --git a/reentr.h b/reentr.h
index 3510fc5..c268851 100644
--- a/reentr.h
+++ b/reentr.h
@@ -41,13 +41,11 @@
 
 #ifdef __hpux
 #   undef HAS_CRYPT_R
-#   undef HAS_DRAND48_R
 #   undef HAS_ENDGRENT_R
 #   undef HAS_ENDPWENT_R
 #   undef HAS_GETGRENT_R
 #   undef HAS_GETPWENT_R
 #   undef HAS_SETLOCALE_R
-#   undef HAS_SRAND48_R
 #   undef HAS_STRERROR_R
 #   define NETDB_R_OBSOLETE
 #endif
@@ -101,9 +99,6 @@
 #ifdef I_NETDB
 #   include <netdb.h>
 #endif
-#ifdef I_STDLIB
-#   include <stdlib.h>	/* drand48_data */
-#endif
 #ifdef I_CRYPT
 #   ifdef I_CRYPT
 #       include <crypt.h>
@@ -150,48 +145,43 @@
 #define REENTRANT_PROTO_I_ISD	33
 #define REENTRANT_PROTO_I_LISBI	34
 #define REENTRANT_PROTO_I_LISD	35
-#define REENTRANT_PROTO_I_LS	36
-#define REENTRANT_PROTO_I_SB	37
-#define REENTRANT_PROTO_I_SBI	38
-#define REENTRANT_PROTO_I_SBIE	39
-#define REENTRANT_PROTO_I_SBIH	40
-#define REENTRANT_PROTO_I_SBIR	41
-#define REENTRANT_PROTO_I_SBWR	42
-#define REENTRANT_PROTO_I_SBWRE	43
-#define REENTRANT_PROTO_I_SD	44
-#define REENTRANT_PROTO_I_ST	45
-#define REENTRANT_PROTO_I_St	46
-#define REENTRANT_PROTO_I_TISD	47
-#define REENTRANT_PROTO_I_TS	48
-#define REENTRANT_PROTO_I_TSBI	49
-#define REENTRANT_PROTO_I_TSBIR	50
-#define REENTRANT_PROTO_I_TSBWR	51
-#define REENTRANT_PROTO_I_TSR	52
-#define REENTRANT_PROTO_I_TsISBWRE	53
-#define REENTRANT_PROTO_I_UISBWRE	54
-#define REENTRANT_PROTO_I_iS	55
-#define REENTRANT_PROTO_I_lS	56
-#define REENTRANT_PROTO_I_uISBWRE	57
-#define REENTRANT_PROTO_S_CBI	58
-#define REENTRANT_PROTO_S_CCSBI	59
-#define REENTRANT_PROTO_S_CIISBIE	60
-#define REENTRANT_PROTO_S_CSBI	61
-#define REENTRANT_PROTO_S_CSBIE	62
-#define REENTRANT_PROTO_S_CWISBIE	63
-#define REENTRANT_PROTO_S_CWISBWIE	64
-#define REENTRANT_PROTO_S_ICSBI	65
-#define REENTRANT_PROTO_S_ISBI	66
-#define REENTRANT_PROTO_S_LISBI	67
-#define REENTRANT_PROTO_S_SBI	68
-#define REENTRANT_PROTO_S_SBIE	69
-#define REENTRANT_PROTO_S_SBW	70
-#define REENTRANT_PROTO_S_TISBI	71
-#define REENTRANT_PROTO_S_TSBI	72
-#define REENTRANT_PROTO_S_TSBIE	73
-#define REENTRANT_PROTO_S_TWISBIE	74
-#define REENTRANT_PROTO_V_D	75
-#define REENTRANT_PROTO_V_H	76
-#define REENTRANT_PROTO_V_ID	77
+#define REENTRANT_PROTO_I_SB	36
+#define REENTRANT_PROTO_I_SBI	37
+#define REENTRANT_PROTO_I_SBIE	38
+#define REENTRANT_PROTO_I_SBIH	39
+#define REENTRANT_PROTO_I_SBIR	40
+#define REENTRANT_PROTO_I_SBWR	41
+#define REENTRANT_PROTO_I_SBWRE	42
+#define REENTRANT_PROTO_I_SD	43
+#define REENTRANT_PROTO_I_TISD	44
+#define REENTRANT_PROTO_I_TS	45
+#define REENTRANT_PROTO_I_TSBI	46
+#define REENTRANT_PROTO_I_TSBIR	47
+#define REENTRANT_PROTO_I_TSBWR	48
+#define REENTRANT_PROTO_I_TSR	49
+#define REENTRANT_PROTO_I_TsISBWRE	50
+#define REENTRANT_PROTO_I_UISBWRE	51
+#define REENTRANT_PROTO_I_uISBWRE	52
+#define REENTRANT_PROTO_S_CBI	53
+#define REENTRANT_PROTO_S_CCSBI	54
+#define REENTRANT_PROTO_S_CIISBIE	55
+#define REENTRANT_PROTO_S_CSBI	56
+#define REENTRANT_PROTO_S_CSBIE	57
+#define REENTRANT_PROTO_S_CWISBIE	58
+#define REENTRANT_PROTO_S_CWISBWIE	59
+#define REENTRANT_PROTO_S_ICSBI	60
+#define REENTRANT_PROTO_S_ISBI	61
+#define REENTRANT_PROTO_S_LISBI	62
+#define REENTRANT_PROTO_S_SBI	63
+#define REENTRANT_PROTO_S_SBIE	64
+#define REENTRANT_PROTO_S_SBW	65
+#define REENTRANT_PROTO_S_TISBI	66
+#define REENTRANT_PROTO_S_TSBI	67
+#define REENTRANT_PROTO_S_TSBIE	68
+#define REENTRANT_PROTO_S_TWISBIE	69
+#define REENTRANT_PROTO_V_D	70
+#define REENTRANT_PROTO_V_H	71
+#define REENTRANT_PROTO_V_ID	72
 
 /* Defines for indicating which special features are supported. */
 
@@ -639,10 +629,6 @@ typedef struct {
 	char*	_ctime_buffer;
 	size_t	_ctime_size;
 #endif /* HAS_CTIME_R */
-#ifdef HAS_DRAND48_R
-	struct drand48_data _drand48_struct;
-	double	_drand48_double;
-#endif /* HAS_DRAND48_R */
 #ifdef HAS_GETGRNAM_R
 	struct group	_grent_struct;
 	char*	_grent_buffer;
@@ -740,18 +726,6 @@ typedef struct {
 	FILE*	_spent_fptr;
 #   endif
 #endif /* HAS_GETSPNAM_R */
-#ifdef HAS_RANDOM_R
-	struct random_data _random_struct;
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_iS
-	int	_random_retval;
-#   endif
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_lS
-	long	_random_retval;
-#   endif
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_St
-	int32_t	_random_retval;
-#   endif
-#endif /* HAS_RANDOM_R */
 #ifdef HAS_READDIR_R
 	struct dirent*	_readdir_struct;
 	size_t	_readdir_size;
@@ -770,9 +744,6 @@ typedef struct {
 	char*	_setlocale_buffer;
 	size_t	_setlocale_size;
 #endif /* HAS_SETLOCALE_R */
-#ifdef HAS_SRANDOM_R
-	struct random_data _srandom_struct;
-#endif /* HAS_SRANDOM_R */
 #ifdef HAS_STRERROR_R
 	char*	_strerror_buffer;
 	size_t	_strerror_size;
@@ -844,15 +815,6 @@ typedef struct {
 #  endif
 #endif /* HAS_CTIME_R */
 
-#ifdef HAS_DRAND48_R
-#  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
-#   undef drand48
-#   if !defined(drand48) && DRAND48_R_PROTO == REENTRANT_PROTO_I_ST
-#       define drand48() (drand48_r(&PL_reentrant_buffer->_drand48_struct, &PL_reentrant_buffer->_drand48_double) == 0 ? PL_reentrant_buffer->_drand48_double : 0)
-#   endif
-#  endif
-#endif /* HAS_DRAND48_R */
-
 #ifdef HAS_ENDGRENT_R
 #  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
 #   undef endgrent
@@ -1324,21 +1286,6 @@ typedef struct {
 #  endif
 #endif /* HAS_GETSPNAM_R */
 
-#ifdef HAS_RANDOM_R
-#  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
-#   undef random
-#   if !defined(random) && RANDOM_R_PROTO == REENTRANT_PROTO_I_iS
-#       define random() (random_r(&PL_reentrant_buffer->_random_retval, &PL_reentrant_buffer->_random_struct) == 0 ? PL_reentrant_buffer->_random_retval : 0)
-#   endif
-#   if !defined(random) && RANDOM_R_PROTO == REENTRANT_PROTO_I_lS
-#       define random() (random_r(&PL_reentrant_buffer->_random_retval, &PL_reentrant_buffer->_random_struct) == 0 ? PL_reentrant_buffer->_random_retval : 0)
-#   endif
-#   if !defined(random) && RANDOM_R_PROTO == REENTRANT_PROTO_I_St
-#       define random() (random_r(&PL_reentrant_buffer->_random_struct, &PL_reentrant_buffer->_random_retval) == 0 ? PL_reentrant_buffer->_random_retval : 0)
-#   endif
-#  endif
-#endif /* HAS_RANDOM_R */
-
 #ifdef HAS_READDIR_R
 #  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
 #   undef readdir
@@ -1444,24 +1391,6 @@ typedef struct {
 #  endif
 #endif /* HAS_SETSERVENT_R */
 
-#ifdef HAS_SRAND48_R
-#  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
-#   undef srand48
-#   if !defined(srand48) && SRAND48_R_PROTO == REENTRANT_PROTO_I_LS
-#       define srand48(a) (srand48_r(a, &PL_reentrant_buffer->_drand48_struct) == 0 ? &PL_reentrant_buffer->_drand48_struct : 0)
-#   endif
-#  endif
-#endif /* HAS_SRAND48_R */
-
-#ifdef HAS_SRANDOM_R
-#  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
-#   undef srandom
-#   if !defined(srandom) && SRANDOM_R_PROTO == REENTRANT_PROTO_I_TS
-#       define srandom(a) (srandom_r(a, &PL_reentrant_buffer->_srandom_struct) == 0 ? &PL_reentrant_buffer->_srandom_struct : 0)
-#   endif
-#  endif
-#endif /* HAS_SRANDOM_R */
-
 #ifdef HAS_STRERROR_R
 #  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
 #   undef strerror
diff --git a/regen/reentr.pl b/regen/reentr.pl
index c5e7129..6dac299 100644
--- a/regen/reentr.pl
+++ b/regen/reentr.pl
@@ -91,13 +91,11 @@ print $h <<EOF;
 
 #ifdef __hpux
 #   undef HAS_CRYPT_R
-#   undef HAS_DRAND48_R
 #   undef HAS_ENDGRENT_R
 #   undef HAS_ENDPWENT_R
 #   undef HAS_GETGRENT_R
 #   undef HAS_GETPWENT_R
 #   undef HAS_SETLOCALE_R
-#   undef HAS_SRAND48_R
 #   undef HAS_STRERROR_R
 #   define NETDB_R_OBSOLETE
 #endif
@@ -151,9 +149,6 @@ print $h <<EOF;
 #ifdef I_NETDB
 #   include <netdb.h>
 #endif
-#ifdef I_STDLIB
-#   include <stdlib.h>	/* drand48_data */
-#endif
 #ifdef I_CRYPT
 #   ifdef I_CRYPT
 #       include <crypt.h>
@@ -504,30 +499,6 @@ EOF
 EOF
 	    pushssif $endif;
 	}
-        elsif ($func =~ /^(drand48|random|srandom)$/) {
-	    pushssif $ifdef;
-	    push @struct, <<EOF;
-	$seent{$func} _${func}_struct;
-EOF
-	    if ($1 eq 'drand48') {
-	        push @struct, <<EOF;
-	double	_${func}_double;
-EOF
-	    } elsif ($1 eq 'random') {
-	    push @struct, <<EOF;
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_iS
-	int	_${func}_retval;
-#   endif
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_lS
-	long	_${func}_retval;
-#   endif
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_St
-	int32_t	_${func}_retval;
-#   endif
-EOF
-	    }
-	    pushssif $endif;
-	}
         elsif ($func =~ /^(getgrnam|getpwnam|getspnam)$/) {
 	    pushssif $ifdef;
 	    # 'genfunc' can be read either as 'generic' or 'genre',
@@ -664,18 +635,12 @@ EOF
 	    my $genfunc = $func;
 	    if ($genfunc =~ /^(?:get|set|end)(pw|gr|host|net|proto|serv|sp)/) {
 		$genfunc = "${1}ent";
-	    } elsif ($genfunc eq 'srand48') {
-		$genfunc = "drand48";
 	    }
 	    my $b = $a;
 	    my $w = '';
 	    substr($b, 0, $seenu{$func}) = '';
-	    if ($func =~ /^random$/) {
-		$true = "PL_reentrant_buffer->_random_retval";
-	    } elsif ($b =~ /R/) {
+	    if ($b =~ /R/) {
 		$true = "PL_reentrant_buffer->_${genfunc}_ptr";
-	    } elsif ($b =~ /T/ && $func eq 'drand48') {
-		$true = "PL_reentrant_buffer->_${genfunc}_double";
 	    } elsif ($b =~ /S/) {
 		if ($func =~ /^readdir/) {
 		    $true = "PL_reentrant_buffer->_${genfunc}_struct";
@@ -706,10 +671,6 @@ EOF
 				  $func =~ /^crypt$/ ?
 				  "PL_reentrant_buffer->_${genfunc}_struct_buffer" :
 				  "&PL_reentrant_buffer->_${genfunc}_struct") :
-			     $_ eq 'T' && $func eq 'drand48' ?
-				 "&PL_reentrant_buffer->_${genfunc}_double" :
-			     $_ =~ /^[ilt]$/ && $func eq 'random' ?
-				 "&PL_reentrant_buffer->_random_retval" :
 				 $_
 			 } split '', $b;
 		$w = ", $w" if length $v;
@@ -1076,7 +1037,6 @@ asctime S	|time	|const struct tm|B_SB|B_SBI|I_SB|I_SBI
 crypt CC	|crypt	|struct crypt_data|B_CCS|B_CCD|D=CRYPTD*
 ctermid	B	|stdio	|		|B_B
 ctime S		|time	|const time_t	|B_SB|B_SBI|I_SB|I_SBI
-drand48		|stdlib	|struct drand48_data	|I_ST|T=double*
 endgrent	|grp	|		|I_H|V_H
 endhostent	|netdb	|		|I_D|V_D|D=struct hostent_data*
 endnetent	|netdb	|		|I_D|V_D|D=struct netent_data*
@@ -1103,7 +1063,6 @@ getservbyname CC|netdb	|struct servent	|I_CCSBWR|S_CCSBI|I_CCSD|D=struct servent
 getservbyport IC|netdb	|struct servent	|I_ICSBWR|S_ICSBI|I_ICSD|D=struct servent_data*
 getservent	|netdb	|struct servent	|I_SBWR|I_SBI|S_SBI|I_SD|D=struct servent_data*
 getspnam C	|shadow	|struct spwd	|I_CSBWR|S_CSBI
-random		|stdlib	|struct random_data|I_iS|I_lS|I_St|i=int*|l=long*|t=int32_t*
 readdir T	|dirent	|struct dirent	|I_TSR|I_TS|T=DIR*
 readdir64 T	|dirent	|struct dirent64|I_TSR|I_TS|T=DIR*
 setgrent	|grp	|		|I_H|V_H
@@ -1113,8 +1072,6 @@ setnetent I	|netdb	|		|I_ID|V_ID|D=struct netent_data*
 setprotoent I	|netdb	|		|I_ID|V_ID|D=struct protoent_data*
 setpwent	|pwd	|		|I_H|V_H
 setservent I	|netdb	|		|I_ID|V_ID|D=struct servent_data*
-srand48 L	|stdlib	|struct drand48_data	|I_LS
-srandom	T	|stdlib	|struct random_data|I_TS|T=unsigned int
 strerror I	|string	|		|I_IBW|I_IBI|B_IBW
 tmpnam B	|stdio	|		|B_B
 ttyname	I	|unistd	|		|I_IBW|I_IBI|B_IBI

@p5pRT
Copy link
Author

p5pRT commented Sep 6, 2013

From @demerphq

On 4 September 2013 03​:33, Tony Cook via RT <perlbug-followup@​perl.org> wrote​:

On Thu Aug 22 23​:39​:36 2013, hmbrand wrote​:

On Thu, 22 Aug 2013 16​:24​:01 -0700, "Tony Cook via RT"
<perlbug-followup@​perl.org> wrote​:

On Thu Aug 08 00​:03​:28 2013, tonyc wrote​:

On Thu Jul 25 00​:00​:27 2013, tonyc wrote​:

c) use our drand48() always, don't bother setting
$Config{drand01} etc.

I've attached two implementations.

The first is as I said above - a purely private to perl
implementation.

But from looking at the perl sources, List-Util uses perl's
seedDrand01() and Drand01(), from from checking CPAN, many CPAN
modules
also use them.

So I've prepared an alternate patch that replaces the macros so
that
modules will use the new random number implementation.

One problem with not updating $Config{randbits} in particular is
that
code that sensibly looks at that value to check is rand() is sane or
not
will be relying on incorrect data.

So I'm wondering whether Configure should be updated to set the new
values for 5.19 and later (I believe Configure is meant to be
roughly
back-copyable.), or not.

No anymore. git helps. Only backportable patches are picked to
maint/older. With git, current Configure belongs to current perl

So yes, I think having Configure in sync would help​:

$ perl -V​:.*rand.*
d_drand48_r='undef';
d_drand48proto='define';
d_random_r='undef';
d_srand48_r='undef';
d_srandom_r='undef';
drand01='drand48()';
drand48_r_proto='0';
randbits='48';
randfunc='drand48';
random_r_proto='0';
randseedtype='long';
srand48_r_proto='0';
srandom_r_proto='0';

If Configure is updated, configure.com will also need to be updated.

tonyc/drandpublic now includes a Configure change to always use the new
built-in drand() implementation.

Thanks for all the work Tony. I appreciate you picked this up.

I have one concern, the internal API makes it difficult/impossible to
use Perls rand function with a private seed/state buffer*.

IOW, it would be better if we provided the _r interfaces internally
(where you must pass in the address of the seed buffer), and then made
the standard defines "fill in" the use of the interpreters seed
buffer. After all you can implement the global state rand() behavior
with a the _r interfaces, but you cant do the reverse.

What this would mean is that​:

Drand01() => macro, equivalent to perl rand()
seedDrand01(x) =>macro, equivalent to perl srand()

Which would then call into​:

freebsd_drand48_generate_double_r(state)
freebsd_drand48_init_r(state,seed)

That way the internals can have their own seed if necessary, without
impacting the rest of the code. This was an issue for me when I
worked on Perl_get_hash_seed in util.c, and had a surprising impact on
how the hash seed initialization code was set up. Having guaranteed
access to an internally implemented drand48_r() would have made it
trivial.

If you dont object id be happy to work on the patch, on the other hand
if you like the idea and wanted to do it Id be happy to read the patch
once its done. :-)

Thanks again for your work,
Yves
* Ok, i guess one could mess with PL_random_state, but that would be nasty.

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Sep 6, 2013

From @demerphq

On 6 September 2013 11​:58, Nicholas Clark <nick@​ccl4.org> wrote​:

On Thu, Aug 08, 2013 at 12​:03​:30AM -0700, Tony Cook via RT wrote​:
All the (other) config.sh values can safely become undef without causing
any code to notice, as long as these 5 remain valid​:

randfunc=freebsd_drand48_generate_double
drand01="freebsd_drand48_generate_double()"
seedfunc="freebsd_drand48_init"
randbits=48
randseedtype=U32

We can remove all the probing code from Configure, and the reentr.[hc] code
that deals with *_r variants, which is (initially) this​:

Configure | 200 ++-----------------------------------------------------
reentr.c | 18 -----
reentr.h | 145 ++++++++++------------------------------
regen/reentr.pl | 45 +------------
4 files changed, 43 insertions(+), 365 deletions(-)

[all tests pass]

but probably can be a lot better as we can delete 9 lines from every potted
config.sh entry for

d\_drand48\_r d\_drand48proto d\_random\_r d\_srand48\_r d\_srandom\_r
drand48\_r\_proto random\_r\_proto srand48\_r\_proto srandom\_r\_proto

along with Glossary, config_h.SH and maybe more.

Not sure if this relates to what you say here above, but...

I just wanted to register that I think only providing a global state
rand implementation is a bad call, and that we should provide the _r
variant internally, and define the macros so they pass in the seed.
That is a way more reusable and extensible design than the opposite.

When I worked on the hash seed logic the lack of an easy way to create
my own state for generating RNGs that would not impact user side
rand() was a real pain in the ass and forced certain decisions to
happen way before they technically needed to. A lot of that PITA would
have vanished if there was an easy way for internals code to have a
private RNG buffer.

Yves
--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2013

From @tonycoz

On Fri Sep 06 04​:02​:51 2013, demerphq wrote​:

On 6 September 2013 11​:58, Nicholas Clark <nick@​ccl4.org> wrote​:

On Thu, Aug 08, 2013 at 12​:03​:30AM -0700, Tony Cook via RT wrote​:
All the (other) config.sh values can safely become undef without
causing
any code to notice, as long as these 5 remain valid​:

randfunc=freebsd_drand48_generate_double
drand01="freebsd_drand48_generate_double()"
seedfunc="freebsd_drand48_init"
randbits=48
randseedtype=U32

We can remove all the probing code from Configure, and the
reentr.[hc] code
that deals with *_r variants, which is (initially) this​:

Configure | 200
++-----------------------------------------------------
reentr.c | 18 -----
reentr.h | 145 ++++++++++------------------------------
regen/reentr.pl | 45 +------------
4 files changed, 43 insertions(+), 365 deletions(-)

[all tests pass]

but probably can be a lot better as we can delete 9 lines from every
potted
config.sh entry for

d\_drand48\_r d\_drand48proto d\_random\_r d\_srand48\_r d\_srandom\_r
drand48\_r\_proto random\_r\_proto srand48\_r\_proto srandom\_r\_proto

along with Glossary, config_h.SH and maybe more.

Not sure if this relates to what you say here above, but...

I just wanted to register that I think only providing a global state
rand implementation is a bad call, and that we should provide the _r
variant internally, and define the macros so they pass in the seed.
That is a way more reusable and extensible design than the opposite.

When I worked on the hash seed logic the lack of an easy way to create
my own state for generating RNGs that would not impact user side
rand() was a real pain in the ass and forced certain decisions to
happen way before they technically needed to. A lot of that PITA would
have vanished if there was an easy way for internals code to have a
private RNG buffer.

I've pushed an updated tonyc/drandpublic branch that replaces the
freebsd_* functions with Perl_drand48_init_r and Perl_drand48_r
implementations that use the supplied buffer instead of working directly
with PL_random_state.

I then added macros Perl_drand48() and Perl_drand48_init() that
implicitly use PL_random_seed so the macro definitions by config.h make
sense.

I added a change to regen/reentr.pl to remove the now unused random_r(),
srandom_r(), drand48_r() and srand48_r() functions.

I haven't updated Configure to remove the units, I believe this should
happen automatically when metaconfig scans the source and finds that the
macros are no longer used.

Tony

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2013

From @tonycoz

0004-perl-115928-we-don-t-use-drand48_r-or-random_r-any-l.patch
From 9d60200f78f0f4520102641542beab8882f6ab1a Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Tue, 10 Sep 2013 10:09:43 +1000
Subject: [PATCH 4/4] [perl #115928] we don't use drand48_r or random_r any
 longer

Removing this should mean that metaconfig will remove the units from
the built Configure
---
 reentr.c        |   18 -------
 reentr.h        |  145 ++++++++++++++-----------------------------------------
 regen/reentr.pl |   45 +----------------
 3 files changed, 38 insertions(+), 170 deletions(-)

diff --git a/reentr.c b/reentr.c
index 31b933c..a5ea192 100644
--- a/reentr.c
+++ b/reentr.c
@@ -40,8 +40,6 @@ Perl_reentrant_size(pTHX) {
 #ifdef HAS_CTIME_R
 	PL_reentrant_buffer->_ctime_size = REENTRANTSMALLSIZE;
 #endif /* HAS_CTIME_R */
-#ifdef HAS_DRAND48_R
-#endif /* HAS_DRAND48_R */
 #ifdef HAS_GETGRNAM_R
 #   if defined(HAS_SYSCONF) && defined(_SC_GETGR_R_SIZE_MAX) && !defined(__GLIBC__)
 	PL_reentrant_buffer->_grent_size = sysconf(_SC_GETGR_R_SIZE_MAX);
@@ -116,8 +114,6 @@ Perl_reentrant_size(pTHX) {
 #       endif
 #   endif 
 #endif /* HAS_GETSPNAM_R */
-#ifdef HAS_RANDOM_R
-#endif /* HAS_RANDOM_R */
 #ifdef HAS_READDIR_R
 	/* This is the size Solaris recommends.
 	 * (though we go static, should use pathconf() instead) */
@@ -131,8 +127,6 @@ Perl_reentrant_size(pTHX) {
 #ifdef HAS_SETLOCALE_R
 	PL_reentrant_buffer->_setlocale_size = REENTRANTSMALLSIZE;
 #endif /* HAS_SETLOCALE_R */
-#ifdef HAS_SRANDOM_R
-#endif /* HAS_SRANDOM_R */
 #ifdef HAS_STRERROR_R
 	PL_reentrant_buffer->_strerror_size = REENTRANTSMALLSIZE;
 #endif /* HAS_STRERROR_R */
@@ -159,8 +153,6 @@ Perl_reentrant_init(pTHX) {
 #ifdef HAS_CTIME_R
 	Newx(PL_reentrant_buffer->_ctime_buffer, PL_reentrant_buffer->_ctime_size, char);
 #endif /* HAS_CTIME_R */
-#ifdef HAS_DRAND48_R
-#endif /* HAS_DRAND48_R */
 #ifdef HAS_GETGRNAM_R
 #   ifdef USE_GRENT_FPTR
 	PL_reentrant_buffer->_grent_fptr = NULL;
@@ -202,8 +194,6 @@ Perl_reentrant_init(pTHX) {
 #   endif
 	Newx(PL_reentrant_buffer->_spent_buffer, PL_reentrant_buffer->_spent_size, char);
 #endif /* HAS_GETSPNAM_R */
-#ifdef HAS_RANDOM_R
-#endif /* HAS_RANDOM_R */
 #ifdef HAS_READDIR_R
 	PL_reentrant_buffer->_readdir_struct = (struct dirent*)safemalloc(PL_reentrant_buffer->_readdir_size);
 #endif /* HAS_READDIR_R */
@@ -213,8 +203,6 @@ Perl_reentrant_init(pTHX) {
 #ifdef HAS_SETLOCALE_R
 	Newx(PL_reentrant_buffer->_setlocale_buffer, PL_reentrant_buffer->_setlocale_size, char);
 #endif /* HAS_SETLOCALE_R */
-#ifdef HAS_SRANDOM_R
-#endif /* HAS_SRANDOM_R */
 #ifdef HAS_STRERROR_R
 	Newx(PL_reentrant_buffer->_strerror_buffer, PL_reentrant_buffer->_strerror_size, char);
 #endif /* HAS_STRERROR_R */
@@ -239,8 +227,6 @@ Perl_reentrant_free(pTHX) {
 #ifdef HAS_CTIME_R
 	Safefree(PL_reentrant_buffer->_ctime_buffer);
 #endif /* HAS_CTIME_R */
-#ifdef HAS_DRAND48_R
-#endif /* HAS_DRAND48_R */
 #ifdef HAS_GETGRNAM_R
 	Safefree(PL_reentrant_buffer->_grent_buffer);
 #endif /* HAS_GETGRNAM_R */
@@ -273,8 +259,6 @@ Perl_reentrant_free(pTHX) {
 #ifdef HAS_GETSPNAM_R
 	Safefree(PL_reentrant_buffer->_spent_buffer);
 #endif /* HAS_GETSPNAM_R */
-#ifdef HAS_RANDOM_R
-#endif /* HAS_RANDOM_R */
 #ifdef HAS_READDIR_R
 	Safefree(PL_reentrant_buffer->_readdir_struct);
 #endif /* HAS_READDIR_R */
@@ -284,8 +268,6 @@ Perl_reentrant_free(pTHX) {
 #ifdef HAS_SETLOCALE_R
 	Safefree(PL_reentrant_buffer->_setlocale_buffer);
 #endif /* HAS_SETLOCALE_R */
-#ifdef HAS_SRANDOM_R
-#endif /* HAS_SRANDOM_R */
 #ifdef HAS_STRERROR_R
 	Safefree(PL_reentrant_buffer->_strerror_buffer);
 #endif /* HAS_STRERROR_R */
diff --git a/reentr.h b/reentr.h
index 3510fc5..c268851 100644
--- a/reentr.h
+++ b/reentr.h
@@ -41,13 +41,11 @@
 
 #ifdef __hpux
 #   undef HAS_CRYPT_R
-#   undef HAS_DRAND48_R
 #   undef HAS_ENDGRENT_R
 #   undef HAS_ENDPWENT_R
 #   undef HAS_GETGRENT_R
 #   undef HAS_GETPWENT_R
 #   undef HAS_SETLOCALE_R
-#   undef HAS_SRAND48_R
 #   undef HAS_STRERROR_R
 #   define NETDB_R_OBSOLETE
 #endif
@@ -101,9 +99,6 @@
 #ifdef I_NETDB
 #   include <netdb.h>
 #endif
-#ifdef I_STDLIB
-#   include <stdlib.h>	/* drand48_data */
-#endif
 #ifdef I_CRYPT
 #   ifdef I_CRYPT
 #       include <crypt.h>
@@ -150,48 +145,43 @@
 #define REENTRANT_PROTO_I_ISD	33
 #define REENTRANT_PROTO_I_LISBI	34
 #define REENTRANT_PROTO_I_LISD	35
-#define REENTRANT_PROTO_I_LS	36
-#define REENTRANT_PROTO_I_SB	37
-#define REENTRANT_PROTO_I_SBI	38
-#define REENTRANT_PROTO_I_SBIE	39
-#define REENTRANT_PROTO_I_SBIH	40
-#define REENTRANT_PROTO_I_SBIR	41
-#define REENTRANT_PROTO_I_SBWR	42
-#define REENTRANT_PROTO_I_SBWRE	43
-#define REENTRANT_PROTO_I_SD	44
-#define REENTRANT_PROTO_I_ST	45
-#define REENTRANT_PROTO_I_St	46
-#define REENTRANT_PROTO_I_TISD	47
-#define REENTRANT_PROTO_I_TS	48
-#define REENTRANT_PROTO_I_TSBI	49
-#define REENTRANT_PROTO_I_TSBIR	50
-#define REENTRANT_PROTO_I_TSBWR	51
-#define REENTRANT_PROTO_I_TSR	52
-#define REENTRANT_PROTO_I_TsISBWRE	53
-#define REENTRANT_PROTO_I_UISBWRE	54
-#define REENTRANT_PROTO_I_iS	55
-#define REENTRANT_PROTO_I_lS	56
-#define REENTRANT_PROTO_I_uISBWRE	57
-#define REENTRANT_PROTO_S_CBI	58
-#define REENTRANT_PROTO_S_CCSBI	59
-#define REENTRANT_PROTO_S_CIISBIE	60
-#define REENTRANT_PROTO_S_CSBI	61
-#define REENTRANT_PROTO_S_CSBIE	62
-#define REENTRANT_PROTO_S_CWISBIE	63
-#define REENTRANT_PROTO_S_CWISBWIE	64
-#define REENTRANT_PROTO_S_ICSBI	65
-#define REENTRANT_PROTO_S_ISBI	66
-#define REENTRANT_PROTO_S_LISBI	67
-#define REENTRANT_PROTO_S_SBI	68
-#define REENTRANT_PROTO_S_SBIE	69
-#define REENTRANT_PROTO_S_SBW	70
-#define REENTRANT_PROTO_S_TISBI	71
-#define REENTRANT_PROTO_S_TSBI	72
-#define REENTRANT_PROTO_S_TSBIE	73
-#define REENTRANT_PROTO_S_TWISBIE	74
-#define REENTRANT_PROTO_V_D	75
-#define REENTRANT_PROTO_V_H	76
-#define REENTRANT_PROTO_V_ID	77
+#define REENTRANT_PROTO_I_SB	36
+#define REENTRANT_PROTO_I_SBI	37
+#define REENTRANT_PROTO_I_SBIE	38
+#define REENTRANT_PROTO_I_SBIH	39
+#define REENTRANT_PROTO_I_SBIR	40
+#define REENTRANT_PROTO_I_SBWR	41
+#define REENTRANT_PROTO_I_SBWRE	42
+#define REENTRANT_PROTO_I_SD	43
+#define REENTRANT_PROTO_I_TISD	44
+#define REENTRANT_PROTO_I_TS	45
+#define REENTRANT_PROTO_I_TSBI	46
+#define REENTRANT_PROTO_I_TSBIR	47
+#define REENTRANT_PROTO_I_TSBWR	48
+#define REENTRANT_PROTO_I_TSR	49
+#define REENTRANT_PROTO_I_TsISBWRE	50
+#define REENTRANT_PROTO_I_UISBWRE	51
+#define REENTRANT_PROTO_I_uISBWRE	52
+#define REENTRANT_PROTO_S_CBI	53
+#define REENTRANT_PROTO_S_CCSBI	54
+#define REENTRANT_PROTO_S_CIISBIE	55
+#define REENTRANT_PROTO_S_CSBI	56
+#define REENTRANT_PROTO_S_CSBIE	57
+#define REENTRANT_PROTO_S_CWISBIE	58
+#define REENTRANT_PROTO_S_CWISBWIE	59
+#define REENTRANT_PROTO_S_ICSBI	60
+#define REENTRANT_PROTO_S_ISBI	61
+#define REENTRANT_PROTO_S_LISBI	62
+#define REENTRANT_PROTO_S_SBI	63
+#define REENTRANT_PROTO_S_SBIE	64
+#define REENTRANT_PROTO_S_SBW	65
+#define REENTRANT_PROTO_S_TISBI	66
+#define REENTRANT_PROTO_S_TSBI	67
+#define REENTRANT_PROTO_S_TSBIE	68
+#define REENTRANT_PROTO_S_TWISBIE	69
+#define REENTRANT_PROTO_V_D	70
+#define REENTRANT_PROTO_V_H	71
+#define REENTRANT_PROTO_V_ID	72
 
 /* Defines for indicating which special features are supported. */
 
@@ -639,10 +629,6 @@ typedef struct {
 	char*	_ctime_buffer;
 	size_t	_ctime_size;
 #endif /* HAS_CTIME_R */
-#ifdef HAS_DRAND48_R
-	struct drand48_data _drand48_struct;
-	double	_drand48_double;
-#endif /* HAS_DRAND48_R */
 #ifdef HAS_GETGRNAM_R
 	struct group	_grent_struct;
 	char*	_grent_buffer;
@@ -740,18 +726,6 @@ typedef struct {
 	FILE*	_spent_fptr;
 #   endif
 #endif /* HAS_GETSPNAM_R */
-#ifdef HAS_RANDOM_R
-	struct random_data _random_struct;
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_iS
-	int	_random_retval;
-#   endif
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_lS
-	long	_random_retval;
-#   endif
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_St
-	int32_t	_random_retval;
-#   endif
-#endif /* HAS_RANDOM_R */
 #ifdef HAS_READDIR_R
 	struct dirent*	_readdir_struct;
 	size_t	_readdir_size;
@@ -770,9 +744,6 @@ typedef struct {
 	char*	_setlocale_buffer;
 	size_t	_setlocale_size;
 #endif /* HAS_SETLOCALE_R */
-#ifdef HAS_SRANDOM_R
-	struct random_data _srandom_struct;
-#endif /* HAS_SRANDOM_R */
 #ifdef HAS_STRERROR_R
 	char*	_strerror_buffer;
 	size_t	_strerror_size;
@@ -844,15 +815,6 @@ typedef struct {
 #  endif
 #endif /* HAS_CTIME_R */
 
-#ifdef HAS_DRAND48_R
-#  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
-#   undef drand48
-#   if !defined(drand48) && DRAND48_R_PROTO == REENTRANT_PROTO_I_ST
-#       define drand48() (drand48_r(&PL_reentrant_buffer->_drand48_struct, &PL_reentrant_buffer->_drand48_double) == 0 ? PL_reentrant_buffer->_drand48_double : 0)
-#   endif
-#  endif
-#endif /* HAS_DRAND48_R */
-
 #ifdef HAS_ENDGRENT_R
 #  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
 #   undef endgrent
@@ -1324,21 +1286,6 @@ typedef struct {
 #  endif
 #endif /* HAS_GETSPNAM_R */
 
-#ifdef HAS_RANDOM_R
-#  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
-#   undef random
-#   if !defined(random) && RANDOM_R_PROTO == REENTRANT_PROTO_I_iS
-#       define random() (random_r(&PL_reentrant_buffer->_random_retval, &PL_reentrant_buffer->_random_struct) == 0 ? PL_reentrant_buffer->_random_retval : 0)
-#   endif
-#   if !defined(random) && RANDOM_R_PROTO == REENTRANT_PROTO_I_lS
-#       define random() (random_r(&PL_reentrant_buffer->_random_retval, &PL_reentrant_buffer->_random_struct) == 0 ? PL_reentrant_buffer->_random_retval : 0)
-#   endif
-#   if !defined(random) && RANDOM_R_PROTO == REENTRANT_PROTO_I_St
-#       define random() (random_r(&PL_reentrant_buffer->_random_struct, &PL_reentrant_buffer->_random_retval) == 0 ? PL_reentrant_buffer->_random_retval : 0)
-#   endif
-#  endif
-#endif /* HAS_RANDOM_R */
-
 #ifdef HAS_READDIR_R
 #  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
 #   undef readdir
@@ -1444,24 +1391,6 @@ typedef struct {
 #  endif
 #endif /* HAS_SETSERVENT_R */
 
-#ifdef HAS_SRAND48_R
-#  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
-#   undef srand48
-#   if !defined(srand48) && SRAND48_R_PROTO == REENTRANT_PROTO_I_LS
-#       define srand48(a) (srand48_r(a, &PL_reentrant_buffer->_drand48_struct) == 0 ? &PL_reentrant_buffer->_drand48_struct : 0)
-#   endif
-#  endif
-#endif /* HAS_SRAND48_R */
-
-#ifdef HAS_SRANDOM_R
-#  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
-#   undef srandom
-#   if !defined(srandom) && SRANDOM_R_PROTO == REENTRANT_PROTO_I_TS
-#       define srandom(a) (srandom_r(a, &PL_reentrant_buffer->_srandom_struct) == 0 ? &PL_reentrant_buffer->_srandom_struct : 0)
-#   endif
-#  endif
-#endif /* HAS_SRANDOM_R */
-
 #ifdef HAS_STRERROR_R
 #  if defined(PERL_REENTR_API) && (PERL_REENTR_API+0 == 1)
 #   undef strerror
diff --git a/regen/reentr.pl b/regen/reentr.pl
index c5e7129..6dac299 100644
--- a/regen/reentr.pl
+++ b/regen/reentr.pl
@@ -91,13 +91,11 @@ print $h <<EOF;
 
 #ifdef __hpux
 #   undef HAS_CRYPT_R
-#   undef HAS_DRAND48_R
 #   undef HAS_ENDGRENT_R
 #   undef HAS_ENDPWENT_R
 #   undef HAS_GETGRENT_R
 #   undef HAS_GETPWENT_R
 #   undef HAS_SETLOCALE_R
-#   undef HAS_SRAND48_R
 #   undef HAS_STRERROR_R
 #   define NETDB_R_OBSOLETE
 #endif
@@ -151,9 +149,6 @@ print $h <<EOF;
 #ifdef I_NETDB
 #   include <netdb.h>
 #endif
-#ifdef I_STDLIB
-#   include <stdlib.h>	/* drand48_data */
-#endif
 #ifdef I_CRYPT
 #   ifdef I_CRYPT
 #       include <crypt.h>
@@ -504,30 +499,6 @@ EOF
 EOF
 	    pushssif $endif;
 	}
-        elsif ($func =~ /^(drand48|random|srandom)$/) {
-	    pushssif $ifdef;
-	    push @struct, <<EOF;
-	$seent{$func} _${func}_struct;
-EOF
-	    if ($1 eq 'drand48') {
-	        push @struct, <<EOF;
-	double	_${func}_double;
-EOF
-	    } elsif ($1 eq 'random') {
-	    push @struct, <<EOF;
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_iS
-	int	_${func}_retval;
-#   endif
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_lS
-	long	_${func}_retval;
-#   endif
-#   if RANDOM_R_PROTO == REENTRANT_PROTO_I_St
-	int32_t	_${func}_retval;
-#   endif
-EOF
-	    }
-	    pushssif $endif;
-	}
         elsif ($func =~ /^(getgrnam|getpwnam|getspnam)$/) {
 	    pushssif $ifdef;
 	    # 'genfunc' can be read either as 'generic' or 'genre',
@@ -664,18 +635,12 @@ EOF
 	    my $genfunc = $func;
 	    if ($genfunc =~ /^(?:get|set|end)(pw|gr|host|net|proto|serv|sp)/) {
 		$genfunc = "${1}ent";
-	    } elsif ($genfunc eq 'srand48') {
-		$genfunc = "drand48";
 	    }
 	    my $b = $a;
 	    my $w = '';
 	    substr($b, 0, $seenu{$func}) = '';
-	    if ($func =~ /^random$/) {
-		$true = "PL_reentrant_buffer->_random_retval";
-	    } elsif ($b =~ /R/) {
+	    if ($b =~ /R/) {
 		$true = "PL_reentrant_buffer->_${genfunc}_ptr";
-	    } elsif ($b =~ /T/ && $func eq 'drand48') {
-		$true = "PL_reentrant_buffer->_${genfunc}_double";
 	    } elsif ($b =~ /S/) {
 		if ($func =~ /^readdir/) {
 		    $true = "PL_reentrant_buffer->_${genfunc}_struct";
@@ -706,10 +671,6 @@ EOF
 				  $func =~ /^crypt$/ ?
 				  "PL_reentrant_buffer->_${genfunc}_struct_buffer" :
 				  "&PL_reentrant_buffer->_${genfunc}_struct") :
-			     $_ eq 'T' && $func eq 'drand48' ?
-				 "&PL_reentrant_buffer->_${genfunc}_double" :
-			     $_ =~ /^[ilt]$/ && $func eq 'random' ?
-				 "&PL_reentrant_buffer->_random_retval" :
 				 $_
 			 } split '', $b;
 		$w = ", $w" if length $v;
@@ -1076,7 +1037,6 @@ asctime S	|time	|const struct tm|B_SB|B_SBI|I_SB|I_SBI
 crypt CC	|crypt	|struct crypt_data|B_CCS|B_CCD|D=CRYPTD*
 ctermid	B	|stdio	|		|B_B
 ctime S		|time	|const time_t	|B_SB|B_SBI|I_SB|I_SBI
-drand48		|stdlib	|struct drand48_data	|I_ST|T=double*
 endgrent	|grp	|		|I_H|V_H
 endhostent	|netdb	|		|I_D|V_D|D=struct hostent_data*
 endnetent	|netdb	|		|I_D|V_D|D=struct netent_data*
@@ -1103,7 +1063,6 @@ getservbyname CC|netdb	|struct servent	|I_CCSBWR|S_CCSBI|I_CCSD|D=struct servent
 getservbyport IC|netdb	|struct servent	|I_ICSBWR|S_ICSBI|I_ICSD|D=struct servent_data*
 getservent	|netdb	|struct servent	|I_SBWR|I_SBI|S_SBI|I_SD|D=struct servent_data*
 getspnam C	|shadow	|struct spwd	|I_CSBWR|S_CSBI
-random		|stdlib	|struct random_data|I_iS|I_lS|I_St|i=int*|l=long*|t=int32_t*
 readdir T	|dirent	|struct dirent	|I_TSR|I_TS|T=DIR*
 readdir64 T	|dirent	|struct dirent64|I_TSR|I_TS|T=DIR*
 setgrent	|grp	|		|I_H|V_H
@@ -1113,8 +1072,6 @@ setnetent I	|netdb	|		|I_ID|V_ID|D=struct netent_data*
 setprotoent I	|netdb	|		|I_ID|V_ID|D=struct protoent_data*
 setpwent	|pwd	|		|I_H|V_H
 setservent I	|netdb	|		|I_ID|V_ID|D=struct servent_data*
-srand48 L	|stdlib	|struct drand48_data	|I_LS
-srandom	T	|stdlib	|struct random_data|I_TS|T=unsigned int
 strerror I	|string	|		|I_IBW|I_IBI|B_IBW
 tmpnam B	|stdio	|		|B_B
 ttyname	I	|unistd	|		|I_IBW|I_IBI|B_IBI
-- 
1.7.10.4

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2013

From @tonycoz

0002-revert-config_h.SH-changes-now-handled-by-Configure.patch
From 0670996e22aee36bdb5568331861ba0e392388b0 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Thu, 29 Aug 2013 14:52:15 +1000
Subject: [PATCH 2/4] revert config_h.SH changes, now handled by Configure

---
 config_h.SH |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/config_h.SH b/config_h.SH
index c2d69f4..be47a6b 100755
--- a/config_h.SH
+++ b/config_h.SH
@@ -3147,10 +3147,10 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
  *	function used to generate normalized random numbers.
  *	Values include 15, 16, 31, and 48.
  */
-#define Drand01()		Perl_drand48()		/**/
-#define Rand_seed_t		U32		/**/
-#define seedDrand01(x)	Perl_drand48_init((Rand_seed_t)x)	/**/
-#define RANDBITS		48		/**/
+#define Drand01()              $drand01                /**/
+#define Rand_seed_t            $randseedtype           /**/
+#define seedDrand01(x) $seedfunc((Rand_seed_t)x)       /**/
+#define RANDBITS               $randbits               /**/
 
 /* Select_fd_set_t:
  *	This symbol holds the type used for the 2nd, 3rd, and 4th
-- 
1.7.10.4

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2013

From @tonycoz

0001-perl-115928-a-consistent-public-rand-implementation.patch
From a343923893c78ace0952133a6397e57a2e9aee28 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Mon, 9 Sep 2013 14:44:57 +1000
Subject: [PATCH 1/4] [perl #115928] a consistent (public) rand()
 implementation

Based on Yves's random branch work.

This version makes the new random number visible to external modules,
for example, List::Util's XS shuffle() implementation.

I've also added a 64-bit implementation when HAS_QUAD is true, this
should be significantly faster, even on 32-bit CPUs.  This is intended to
produce exactly the same sequence as the original implementation.

The original version of this commit retained the "freebsd" name from
Yves's original work for the function and data structure names.  I've
removed "freebsd" from most function names so the name isn't an issue
if we choose to replace the implementation,
---
 config_h.SH |    8 ++---
 embed.fnc   |    2 ++
 embedvar.h  |    1 +
 intrpvar.h  |    2 ++
 pp.c        |    4 ---
 proto.h     |   10 ++++++
 sv.c        |    1 +
 t/op/rand.t |    7 ++++-
 uconfig.h   |    8 ++---
 util.c      |  100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 util.h      |   27 ++++++++++++++++
 11 files changed, 157 insertions(+), 13 deletions(-)

diff --git a/config_h.SH b/config_h.SH
index 4af9925..c2d69f4 100755
--- a/config_h.SH
+++ b/config_h.SH
@@ -3147,10 +3147,10 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
  *	function used to generate normalized random numbers.
  *	Values include 15, 16, 31, and 48.
  */
-#define Drand01()		$drand01		/**/
-#define Rand_seed_t		$randseedtype		/**/
-#define seedDrand01(x)	$seedfunc((Rand_seed_t)x)	/**/
-#define RANDBITS		$randbits		/**/
+#define Drand01()		Perl_drand48()		/**/
+#define Rand_seed_t		U32		/**/
+#define seedDrand01(x)	Perl_drand48_init((Rand_seed_t)x)	/**/
+#define RANDBITS		48		/**/
 
 /* Select_fd_set_t:
  *	This symbol holds the type used for the 2nd, 3rd, and 4th
diff --git a/embed.fnc b/embed.fnc
index 0f686d4..2fef45f 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -1571,6 +1571,8 @@ p	|I32	|wait4pid	|Pid_t pid|NN int* statusp|int flags
 : Used in locale.c and perl.c
 p	|U32	|parse_unicode_opts|NN const char **popt
 Ap	|U32	|seed
+Xpno	|double	|drand48_r	|NN perl_drand48_t *random_state
+Xpno	|void	|drand48_init_r |NN perl_drand48_t *random_state|U32 seed
 : Only used in perl.c
 p        |void        |get_hash_seed        |NN unsigned char * const seed_buffer
 : Used in doio.c, pp_hot.c, pp_sys.c
diff --git a/embedvar.h b/embedvar.h
index 3643bd1..7c721ed 100644
--- a/embedvar.h
+++ b/embedvar.h
@@ -243,6 +243,7 @@
 #define PL_psig_pend		(vTHX->Ipsig_pend)
 #define PL_psig_ptr		(vTHX->Ipsig_ptr)
 #define PL_ptr_table		(vTHX->Iptr_table)
+#define PL_random_state		(vTHX->Irandom_state)
 #define PL_reentrant_buffer	(vTHX->Ireentrant_buffer)
 #define PL_reentrant_retint	(vTHX->Ireentrant_retint)
 #define PL_reg_curpm		(vTHX->Ireg_curpm)
diff --git a/intrpvar.h b/intrpvar.h
index c6ee593..768267b 100644
--- a/intrpvar.h
+++ b/intrpvar.h
@@ -784,6 +784,8 @@ PERLVARA(I, op_exec_cnt, OP_max+2, UV)	/* Counts of executed OPs of the given ty
                                            DEBUGGING is enabled, too. */
 #endif
 
+PERLVAR(I, random_state, PL_RANDOM_STATE_TYPE)
+
 /* If you are adding a U8 or U16, check to see if there are 'Space' comments
  * above on where there are gaps which currently will be structure padding.  */
 
diff --git a/pp.c b/pp.c
index 6fc6c9f..9dbe2f8 100644
--- a/pp.c
+++ b/pp.c
@@ -2712,10 +2712,6 @@ PP(pp_sin)
    --Jarkko Hietaniemi	27 September 1998
  */
 
-#ifndef HAS_DRAND48_PROTO
-extern double drand48 (void);
-#endif
-
 PP(pp_rand)
 {
     dVAR;
diff --git a/proto.h b/proto.h
index 7281242..c4d52ff 100644
--- a/proto.h
+++ b/proto.h
@@ -1024,6 +1024,16 @@ PERL_CALLCONV void	Perl_dounwind(pTHX_ I32 cxix);
 PERL_CALLCONV I32	Perl_dowantarray(pTHX)
 			__attribute__warn_unused_result__;
 
+PERL_CALLCONV void	Perl_drand48_init_r(perl_drand48_t *random_state, U32 seed)
+			__attribute__nonnull__(1);
+#define PERL_ARGS_ASSERT_DRAND48_INIT_R	\
+	assert(random_state)
+
+PERL_CALLCONV double	Perl_drand48_r(perl_drand48_t *random_state)
+			__attribute__nonnull__(1);
+#define PERL_ARGS_ASSERT_DRAND48_R	\
+	assert(random_state)
+
 PERL_CALLCONV void	Perl_dump_all(pTHX);
 PERL_CALLCONV void	Perl_dump_all_perl(pTHX_ bool justperl);
 PERL_CALLCONV void	Perl_dump_eval(pTHX);
diff --git a/sv.c b/sv.c
index e7be001..bfbe38b 100644
--- a/sv.c
+++ b/sv.c
@@ -13439,6 +13439,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_last_swash_slen	= 0;
 
     PL_srand_called	= proto_perl->Isrand_called;
+    Copy(&(proto_perl->Irandom_state), &PL_random_state, 1, PL_RANDOM_STATE_TYPE);
 
     if (flags & CLONEf_COPY_STACKS) {
 	/* next allocation will be PL_tmps_stack[PL_tmps_ix+1] */
diff --git a/t/op/rand.t b/t/op/rand.t
index 24b2bf9..90d1c37 100644
--- a/t/op/rand.t
+++ b/t/op/rand.t
@@ -24,7 +24,7 @@ use strict;
 use Config;
 
 require "test.pl";
-plan(tests => 8);
+plan(tests => 10);
 
 
 my $reps = 15000;	# How many times to try rand each time.
@@ -242,3 +242,8 @@ DIAG
     ok($r < 1,        'rand() without args is under 1');
 }
 
+{ # [perl #115928] use a standard rand() implementation
+    srand(1);
+    is(int rand(1000), 41, "our own implementation behaves consistently");
+    is(int rand(1000), 454, "and still consistently");
+}
diff --git a/uconfig.h b/uconfig.h
index 2ae2ff2..3e206dd 100644
--- a/uconfig.h
+++ b/uconfig.h
@@ -3112,9 +3112,9 @@
  *	function used to generate normalized random numbers.
  *	Values include 15, 16, 31, and 48.
  */
-#define Drand01()		((rand() & 0x7FFF) / (double) ((unsigned long)1 << 15))		/**/
-#define Rand_seed_t		int		/**/
-#define seedDrand01(x)	srand((Rand_seed_t)x)	/**/
+#define Drand01()		Perl_drand48()		/**/
+#define Rand_seed_t		U32		/**/
+#define seedDrand01(x)	Perl_drand48_init((Rand_seed_t)x)	/**/
 #define RANDBITS		48		/**/
 
 /* Select_fd_set_t:
@@ -4753,6 +4753,6 @@
 #endif
 
 /* Generated from:
- * 3631b2b781d1779dc1855cb35ab72d5176a9eb36a527f74231c7e3f274021182 config_h.SH
+ * eea5809659d1cac397ca3a1a48f51bcb5bfc60eb2dca2ef00b9b2015ee87729a config_h.SH
  * 3dc6c26adfbf4f2e111d90b34d50e317e18555a76a270fbac2899d08a42f2fd1 uconfig.sh
  * ex: set ro: */
diff --git a/util.c b/util.c
index d2380b2..9c387c1 100644
--- a/util.c
+++ b/util.c
@@ -37,6 +37,9 @@
 #endif
 #endif
 
+#include <math.h>
+#include <stdlib.h>
+
 #ifdef __Lynx__
 /* Missing protos on LynxOS */
 int putenv(char *);
@@ -6179,6 +6182,103 @@ Perl_get_re_arg(pTHX_ SV *sv) {
 }
 
 /*
+ * This code is derived from drand48() implementation from FreeBSD,
+ * found in lib/libc/gen/_rand48.c.
+ *
+ * The U64 implementation is original, based on the POSIX
+ * specification for drand48().
+ */
+
+/*
+* Copyright (c) 1993 Martin Birgmeier
+* All rights reserved.
+*
+* You may redistribute unmodified or modified versions of this source
+* code provided that the above copyright notice and this and the
+* following conditions are retained.
+*
+* This software is provided ``as is'', and comes with no warranties
+* of any kind. I shall in no event be liable for anything that happens
+* to anyone/anything when using this software.
+*/
+
+#define FREEBSD_DRAND48_SEED_0   (0x330e)
+
+#ifdef PERL_DRAND48_QUAD
+
+#define DRAND48_MULT 0x5deece66d
+#define DRAND48_ADD  0xb
+#define DRAND48_MASK 0xffffffffffff
+
+#else
+
+#define FREEBSD_DRAND48_SEED_1   (0xabcd)
+#define FREEBSD_DRAND48_SEED_2   (0x1234)
+#define FREEBSD_DRAND48_MULT_0   (0xe66d)
+#define FREEBSD_DRAND48_MULT_1   (0xdeec)
+#define FREEBSD_DRAND48_MULT_2   (0x0005)
+#define FREEBSD_DRAND48_ADD      (0x000b)
+
+const unsigned short _rand48_mult[3] = {
+                FREEBSD_DRAND48_MULT_0,
+                FREEBSD_DRAND48_MULT_1,
+                FREEBSD_DRAND48_MULT_2
+};
+const unsigned short _rand48_add = FREEBSD_DRAND48_ADD;
+
+#endif
+
+void
+Perl_drand48_init_r(perl_drand48_t *random_state, U32 seed)
+{
+    PERL_ARGS_ASSERT_DRAND48_INIT_R;
+
+#ifdef PERL_DRAND48_QUAD
+    *random_state = FREEBSD_DRAND48_SEED_0 + ((U64TYPE)seed << 16);
+#else
+    random_state->seed[0] = FREEBSD_DRAND48_SEED_0;
+    random_state->seed[1] = (U16) seed;
+    random_state->seed[2] = (U16) (seed >> 16);
+#endif
+}
+
+double
+Perl_drand48_r(perl_drand48_t *random_state)
+{
+    PERL_ARGS_ASSERT_DRAND48_R;
+
+#ifdef PERL_DRAND48_QUAD
+    *random_state = (*random_state * DRAND48_MULT + DRAND48_ADD)
+        & DRAND48_MASK;
+
+    return ldexp(*random_state, -48);
+#else
+    U32 accu;
+    U16 temp[2];
+
+    accu = (U32) _rand48_mult[0] * (U32) random_state->seed[0]
+         + (U32) _rand48_add;
+    temp[0] = (U16) accu;        /* lower 16 bits */
+    accu >>= sizeof(U16) * 8;
+    accu += (U32) _rand48_mult[0] * (U32) random_state->seed[1]
+          + (U32) _rand48_mult[1] * (U32) random_state->seed[0];
+    temp[1] = (U16) accu;        /* middle 16 bits */
+    accu >>= sizeof(U16) * 8;
+    accu += _rand48_mult[0] * random_state->seed[2]
+          + _rand48_mult[1] * random_state->seed[1]
+          + _rand48_mult[2] * random_state->seed[0];
+    random_state->seed[0] = temp[0];
+    random_state->seed[1] = temp[1];
+    random_state->seed[2] = (U16) accu;
+
+    return ldexp((double) random_state->seed[0], -48) +
+           ldexp((double) random_state->seed[1], -32) +
+           ldexp((double) random_state->seed[2], -16);
+#endif
+}
+ 
+
+/*
  * Local variables:
  * c-indentation-style: bsd
  * c-basic-offset: 4
diff --git a/util.h b/util.h
index ed133c4..4e5b97d 100644
--- a/util.h
+++ b/util.h
@@ -52,6 +52,33 @@ This is a synonym for (! foldEQ_locale())
 #define ibcmp(s1, s2, len)         cBOOL(! foldEQ(s1, s2, len))
 #define ibcmp_locale(s1, s2, len)  cBOOL(! foldEQ_locale(s1, s2, len))
 
+/* perl.h undefs HAS_QUAD if IV isn't 64-bit */
+#ifdef U64TYPE
+/* use a faster implementation when quads are available */
+#define PERL_DRAND48_QUAD
+#endif
+
+#ifdef PERL_DRAND48_QUAD
+
+/* U64 is only defined under PERL_CORE, but this needs to be visible
+ * elsewhere so the definition of PerlInterpreter is complete.
+ */
+typedef U64TYPE perl_drand48_t;
+
+#else
+
+struct PERL_DRAND48_T {
+    U16 seed[3];
+};
+
+typedef struct PERL_DRAND48_T perl_drand48_t;
+
+#endif
+
+#define PL_RANDOM_STATE_TYPE perl_drand48_t
+
+#define Perl_drand48_init(seed) (Perl_drand48_init_r(&PL_random_state, (seed)))
+#define Perl_drand48() (Perl_drand48_r(&PL_random_state))
 
 /*
  * Local variables:
-- 
1.7.10.4

@p5pRT
Copy link
Author

p5pRT commented Sep 10, 2013

From @tonycoz

0003-perl-115928-Configure-now-selects-our-internal-drand.patch
From e2cc96bceca8a4a41422ea33b8d5bbf3e590ef10 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Mon, 9 Sep 2013 14:06:35 +1000
Subject: [PATCH 3/4] [perl #115928] Configure now selects our internal
 drand48()

---
 Configure                      |  123 ++--------------------------------------
 Cross/config.sh-arm-linux      |    8 +--
 Cross/config.sh-arm-linux-n770 |    8 +--
 NetWare/config.wc              |   10 ++--
 uconfig.h                      |   12 ++--
 uconfig.sh                     |    8 +--
 win32/config.ce                |   10 ++--
 win32/config.gc                |   10 ++--
 win32/config.vc                |   10 ++--
 9 files changed, 44 insertions(+), 155 deletions(-)

diff --git a/Configure b/Configure
index 7976c13..74806ef 100755
--- a/Configure
+++ b/Configure
@@ -19489,26 +19489,7 @@ esac
 
 : How can we generate normalized random numbers ?
 echo " "
-echo "Looking for a random number function..." >&4
-case "$randfunc" in
-'')
-	if set drand48 val -f; eval $csym; $val; then
-		dflt="drand48"
-		echo "Good, found drand48()." >&4
-	elif set random val -f; eval $csym; $val; then
-		dflt="random"
-		echo "OK, found random()." >&4
-	else
-		dflt="rand"
-		echo "Yuck, looks like I have to use rand()." >&4
-	fi
-	echo " "
-	;;
-*)
-	dflt="$randfunc"
-	;;
-esac
-cont=true
+echo "Using our internal random number implementation..." >&4
 
 case "$ccflags" in
 *-Dmy_rand=*|*-Dmy_srand=*)
@@ -19519,103 +19500,11 @@ case "$ccflags" in
 	;;
 esac
 
-while $test "$cont"; do
-	rp="Use which function to generate random numbers?"
-	. ./myread
-	if $test "$ans" = "$dflt"; then
-		: null
-	else
-		randbits=''
-	fi
-	randfunc="$ans"
-	if set $ans val -f; eval $csym; $val; then
-		cont=''
-	else
-		dflt=y
-		rp="I cannot find function $ans. Use that name anyway?"
-		. ./myread
-		dflt=rand
-		case "$ans" in
-			[yY]*) cont='';;
-		esac
-	fi
-	case "$cont" in
-	'')
-		case "$randfunc" in
-		drand48)
-			drand01="drand48()"
-			seedfunc="srand48"
-			randbits=48
-			randseedtype=long
-			;;
-		rand|random)
-			case "$randbits" in
-			'')
-echo "Checking to see how many bits your $randfunc() function produces..." >&4
-				$cat >try.c <<EOCP
-#$i_unistd I_UNISTD
-#$i_stdlib I_STDLIB
-#include <stdio.h>
-#ifdef I_UNISTD
-#  include <unistd.h>
-#endif
-#ifdef I_STDLIB
-#  include <stdlib.h>
-#endif
-int main()
-{
-	int i;
-	unsigned long tmp;
-	unsigned long max = 0L;
-
-	for (i = 1000; i; i--) {
-		tmp = (unsigned long) $randfunc();
-		if (tmp > max) max = tmp;
-	}
-	for (i = 0; max; i++)
-		max /= 2;
-	printf("%d\n",i);
-}
-EOCP
-				set try
-				if eval $compile_ok; then
-					dflt=`try`
-				else
-					dflt='?'
-					echo "(I can't seem to compile the test program...)"
-				fi
-				;;
-			*)
-				dflt="$randbits"
-				;;
-			esac
-			rp="How many bits does your $randfunc() function produce?"
-			. ./myread
-			randbits="$ans"
-			$rm_try
-			drand01="($randfunc() / (double) ((unsigned long)1 << $randbits))"
-			seedfunc="s$randfunc"
-			randseedtype=unsigned
-			;;
-		*)
-			dflt="31"
-			rp="How many bits does your $randfunc() function produce?"
-			. ./myread
-			randbits="$ans"
-			seedfunc="s$randfunc"
-			drand01="($randfunc() / (double) ((unsigned long)1 << $randbits))"
-			if set $seedfunc val -f; eval $csym; $val; then
-				echo "(Using $seedfunc() to seed random generator)"
-			else
-				echo "(Warning: no $seedfunc() to seed random generator)"
-				seedfunc=rand
-			fi
-			randseedtype=unsigned
-			;;
-		esac
-		;;
-	esac
-done
+randfunc=Perl_drand48
+drand01="Perl_drand48()"
+seedfunc="Perl_drand48_init"
+randbits=48
+randseedtype=U32
 
 : Check how to flush
 echo " "
diff --git a/Cross/config.sh-arm-linux b/Cross/config.sh-arm-linux
index fea06f1..07fc8d2 100644
--- a/Cross/config.sh-arm-linux
+++ b/Cross/config.sh-arm-linux
@@ -556,7 +556,7 @@ direntrytype='struct dirent'
 dlext='so'
 dlsrc='dl_dlopen.xs'
 doublesize='8'
-drand01='drand48()'
+drand01='Perl_drand48()'
 drand48_r_proto='0'
 dtrace=''
 dynamic_ext='B ByteLoader Cwd Data/Dumper Devel/DProf Devel/PPPort Devel/Peek Digest/MD5 Encode Fcntl File/Glob Filter/Util/Call I18N/Langinfo IO IPC/SysV List/Util MIME/Base64 Opcode POSIX PerlIO/encoding PerlIO/scalar PerlIO/via SDBM_File Socket Storable Sys/Hostname Sys/Syslog Time/HiRes Unicode/Collate Unicode/Normalize XS/APItest XS/Typemap attributes re threads threads/shared'
@@ -882,9 +882,9 @@ ptrsize='4'
 quadkind='3'
 quadtype='long long'
 randbits='48'
-randfunc='drand48'
+randfunc='Perl_drand48'
 random_r_proto='0'
-randseedtype='long'
+randseedtype='U32'
 ranlib=':'
 rd_nodata='-1'
 readdir64_r_proto='0'
@@ -915,7 +915,7 @@ sched_yield='sched_yield()'
 scriptdir='/usr/bin'
 scriptdirexp='/usr/bin'
 sed='sed'
-seedfunc='srand48'
+seedfunc='Perl_drand48_init'
 selectminbits='32'
 selecttype='fd_set *'
 sendmail=''
diff --git a/Cross/config.sh-arm-linux-n770 b/Cross/config.sh-arm-linux-n770
index c3b8daf..e3ebe6a 100644
--- a/Cross/config.sh-arm-linux-n770
+++ b/Cross/config.sh-arm-linux-n770
@@ -529,7 +529,7 @@ direntrytype='struct dirent'
 dlext='so'
 dlsrc='dl_dlopen.xs'
 doublesize='8'
-drand01='drand48()'
+drand01='Perl_drand48()'
 drand48_r_proto='0'
 dynamic_ext='B ByteLoader Cwd Data/Dumper Devel/DProf Devel/PPPort Devel/Peek Digest/MD5 Encode Fcntl File/Glob Filter/Util/Call I18N/Langinfo IO IPC/SysV List/Util MIME/Base64 Opcode POSIX PerlIO/encoding PerlIO/scalar PerlIO/via SDBM_File Socket Storable Sys/Hostname Sys/Syslog Time/HiRes Unicode/Collate Unicode/Normalize XS/APItest XS/Typemap attributes re threads threads/shared'
 eagain='EAGAIN'
@@ -852,9 +852,9 @@ ptrsize='4'
 quadkind='3'
 quadtype='long long'
 randbits='48'
-randfunc='drand48'
+randfunc='Perl_drand48'
 random_r_proto='0'
-randseedtype='long'
+randseedtype='U32'
 ranlib=':'
 rd_nodata='-1'
 readdir64_r_proto='0'
@@ -881,7 +881,7 @@ sched_yield='sched_yield()'
 scriptdir='/usr/bin'
 scriptdirexp='/usr/bin'
 sed='sed'
-seedfunc='srand48'
+seedfunc='Perl_drand48_init'
 selectminbits='32'
 selecttype='fd_set *'
 sendmail=''
diff --git a/NetWare/config.wc b/NetWare/config.wc
index 1182d47..016748d 100644
--- a/NetWare/config.wc
+++ b/NetWare/config.wc
@@ -547,7 +547,7 @@ direntrytype='DIR'
 dlext='nlm'
 dlsrc='dl_netware.xs'
 doublesize='8'
-drand01='(rand()/(double)((unsigned)1<<RANDBITS))'
+drand01='Perl_drand48()'
 drand48_r_proto='0'
 dtrace=''
 dynamic_ext='Socket IO Fcntl Opcode SDBM_File attributes'
@@ -854,10 +854,10 @@ prototype='define'
 ptrsize='4'
 quadkind='5'
 quadtype='__int64'
-randbits='15'
-randfunc='rand'
+randbits='48'
+randfunc='Perl_drand48'
 random_r_proto='0'
-randseedtype='unsigned'
+randseedtype='U32'
 ranlib='rem'
 rd_nodata='-1'
 readdir64_r_proto='0'
@@ -887,7 +887,7 @@ sched_yield=''
 scriptdir='~INST_TOP~~INST_VER~\bin'
 scriptdirexp='~INST_TOP~~INST_VER~\bin'
 sed='sed'
-seedfunc='srand'
+seedfunc='Perl_drand48_init'
 selectminbits='32'
 selecttype='fd_set *'
 sendmail='blat'
diff --git a/uconfig.h b/uconfig.h
index 3e206dd..1a59f23 100644
--- a/uconfig.h
+++ b/uconfig.h
@@ -3112,10 +3112,10 @@
  *	function used to generate normalized random numbers.
  *	Values include 15, 16, 31, and 48.
  */
-#define Drand01()		Perl_drand48()		/**/
-#define Rand_seed_t		U32		/**/
-#define seedDrand01(x)	Perl_drand48_init((Rand_seed_t)x)	/**/
-#define RANDBITS		48		/**/
+#define Drand01()              Perl_drand48()                /**/
+#define Rand_seed_t            U32           /**/
+#define seedDrand01(x) Perl_drand48_init((Rand_seed_t)x)       /**/
+#define RANDBITS               48               /**/
 
 /* Select_fd_set_t:
  *	This symbol holds the type used for the 2nd, 3rd, and 4th
@@ -4753,6 +4753,6 @@
 #endif
 
 /* Generated from:
- * eea5809659d1cac397ca3a1a48f51bcb5bfc60eb2dca2ef00b9b2015ee87729a config_h.SH
- * 3dc6c26adfbf4f2e111d90b34d50e317e18555a76a270fbac2899d08a42f2fd1 uconfig.sh
+ * fd2554fe3bee85bee863afd558a83caa6c1a317e9a044639199eda0827db903e config_h.SH
+ * 2a46be0c2dea164ef0186898854f667c064d678c6927d13e926c1bb37d9d4d0e uconfig.sh
  * ex: set ro: */
diff --git a/uconfig.sh b/uconfig.sh
index 374e65d..00f06d6 100644
--- a/uconfig.sh
+++ b/uconfig.sh
@@ -491,7 +491,7 @@ db_version_patch='0'
 defvoidused=1
 direntrytype='struct dirent'
 doublesize='8'
-drand01="((rand() & 0x7FFF) / (double) ((unsigned long)1 << 15))"
+drand01="Perl_drand48()"
 drand48_r_proto='0'
 dtrace=''
 eagain='EAGAIN'
@@ -691,9 +691,9 @@ ptrsize='4'
 quadkind='4'
 quadtype='int64_t'
 randbits='48'
-randfunc='drand48'
+randfunc='Perl_drand48'
 random_r_proto='0'
-randseedtype='int'
+randseedtype='U32'
 rd_nodata='-1'
 readdir64_r_proto='0'
 readdir_r_proto='0'
@@ -717,7 +717,7 @@ sSCNfldbl='"llf"'
 sched_yield='sched_yield()'
 scriptdir='/usr/local/bin'
 scriptdirexp='/usr/local/bin'
-seedfunc='srand'
+seedfunc='Perl_drand48_init'
 selectminbits='32'
 selecttype=int
 setgrent_r_proto='0'
diff --git a/win32/config.ce b/win32/config.ce
index c3e3678..46c0673 100644
--- a/win32/config.ce
+++ b/win32/config.ce
@@ -543,7 +543,7 @@ direntrytype='struct direct'
 dlext='dll'
 dlsrc='dl_win32.xs'
 doublesize='8'
-drand01='(rand()/(double)((unsigned)1<<RANDBITS))'
+drand01='Perl_drand48()'
 drand48_r_proto='0'
 dtrace=''
 dynamic_ext='Socket IO Fcntl Opcode SDBM_File attributes'
@@ -844,10 +844,10 @@ prototype='define'
 ptrsize='4'
 quadkind='5'
 quadtype='__int64'
-randbits='15'
-randfunc='rand'
+randbits='48'
+randfunc='Perl_drand48'
 random_r_proto='0'
-randseedtype='unsigned'
+randseedtype='U32'
 ranlib='rem'
 rd_nodata='-1'
 readdir64_r_proto='0'
@@ -877,7 +877,7 @@ sched_yield=''
 scriptdir='~INST_TOP~~INST_VER~\bin'
 scriptdirexp='~INST_TOP~~INST_VER~\bin'
 sed='sed'
-seedfunc='srand'
+seedfunc='Perl_drand48_init'
 selectminbits='32'
 selecttype='Perl_fd_set *'
 sendmail='blat'
diff --git a/win32/config.gc b/win32/config.gc
index ca098f3..d816795 100644
--- a/win32/config.gc
+++ b/win32/config.gc
@@ -545,7 +545,7 @@ dlext='dll'
 dlltool='~ARCHPREFIX~dlltool'
 dlsrc='dl_win32.xs'
 doublesize='8'
-drand01='(rand()/(double)((unsigned)1<<RANDBITS))'
+drand01='Perl_drand48()'
 drand48_r_proto='0'
 dtrace=''
 dynamic_ext='Socket IO Fcntl Opcode SDBM_File attributes'
@@ -877,10 +877,10 @@ prototype='define'
 ptrsize='4'
 quadkind='3'
 quadtype='long long'
-randbits='15'
-randfunc='rand'
+randbits='48'
+randfunc='Perl_drand48'
 random_r_proto='0'
-randseedtype='unsigned'
+randseedtype='U32'
 ranlib='rem'
 rd_nodata='-1'
 readdir64_r_proto='0'
@@ -912,7 +912,7 @@ sched_yield=''
 scriptdir='~INST_TOP~~INST_VER~\bin'
 scriptdirexp='~INST_TOP~~INST_VER~\bin'
 sed='sed'
-seedfunc='srand'
+seedfunc='Perl_drand48_init'
 selectminbits='32'
 selecttype='Perl_fd_set *'
 sendmail='blat'
diff --git a/win32/config.vc b/win32/config.vc
index 829e0b4..fbfd7ce 100644
--- a/win32/config.vc
+++ b/win32/config.vc
@@ -544,7 +544,7 @@ direntrytype='struct direct'
 dlext='dll'
 dlsrc='dl_win32.xs'
 doublesize='8'
-drand01='(rand()/(double)((unsigned)1<<RANDBITS))'
+drand01='Perl_drand48()'
 drand48_r_proto='0'
 dtrace=''
 dynamic_ext='Socket IO Fcntl Opcode SDBM_File attributes'
@@ -876,10 +876,10 @@ prototype='define'
 ptrsize='4'
 quadkind='5'
 quadtype='__int64'
-randbits='15'
-randfunc='rand'
+randbits='48'
+randfunc='Perl_drand48'
 random_r_proto='0'
-randseedtype='unsigned'
+randseedtype='U32'
 ranlib='rem'
 rd_nodata='-1'
 readdir64_r_proto='0'
@@ -911,7 +911,7 @@ sched_yield=''
 scriptdir='~INST_TOP~~INST_VER~\bin'
 scriptdirexp='~INST_TOP~~INST_VER~\bin'
 sed='sed'
-seedfunc='srand'
+seedfunc='Perl_drand48_init'
 selectminbits='32'
 selecttype='Perl_fd_set *'
 sendmail='blat'
-- 
1.7.10.4

@p5pRT
Copy link
Author

p5pRT commented Sep 12, 2013

From @nwc10

On Fri, Sep 06, 2013 at 01​:02​:03PM +0200, demerphq wrote​:

Not sure if this relates to what you say here above, but...

I think that it was independent.

I just wanted to register that I think only providing a global state
rand implementation is a bad call, and that we should provide the _r
variant internally, and define the macros so they pass in the seed.
That is a way more reusable and extensible design than the opposite.

When I worked on the hash seed logic the lack of an easy way to create
my own state for generating RNGs that would not impact user side
rand() was a real pain in the ass and forced certain decisions to
happen way before they technically needed to. A lot of that PITA would
have vanished if there was an easy way for internals code to have a
private RNG buffer.

I think that you'd said this before somewhere, because I vaguely remember it.
But I'd not thought of it.

Yes, agree. It makes sense. It makes things a lot more flexible, and I don't
think that it's any more complex.

On Fri, Sep 06, 2013 at 12​:57​:26PM +0200, demerphq wrote​:

IOW, it would be better if we provided the _r interfaces internally
(where you must pass in the address of the seed buffer), and then made
the standard defines "fill in" the use of the interpreters seed
buffer. After all you can implement the global state rand() behavior
with a the _r interfaces, but you cant do the reverse.

If you dont object id be happy to work on the patch, on the other hand
if you like the idea and wanted to do it Id be happy to read the patch
once its done. :-)

Seems that Tony has already done this, but I don't think that he asked RT
to send his update to the list, and the default is not to​:

https://rt-archive.perl.org/perl5/Ticket/Display.html?id=115928#txn-1252961

Thanks again for your work,

Ditto.

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented Sep 12, 2013

From @demerphq

On 12 September 2013 16​:55, Nicholas Clark <nick@​ccl4.org> wrote​:

Seems that Tony has already done this, but I don't think that he asked RT
to send his update to the list, and the default is not to​:

https://rt-archive.perl.org/perl5/Ticket/Display.html?id=115928#txn-1252961

Oh goodie. I can clean stuff up once that is applied. Thanks for noticing!

cheers,
Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Sep 13, 2013

From @tonycoz

On Thu Sep 12 07​:56​:27 2013, nicholas wrote​:

Seems that Tony has already done this, but I don't think that he asked
RT
to send his update to the list, and the default is not to​:

https://rt-archive.perl.org/perl5/Ticket/Display.html?id=115928#txn-1252961

It looks like clicking "Add More Files" removes the CC, which I didn't
notice.

Tony

@p5pRT
Copy link
Author

p5pRT commented Sep 13, 2013

From @bulk88

On Thu Sep 12 17​:58​:03 2013, tonyc wrote​:

On Thu Sep 12 07​:56​:27 2013, nicholas wrote​:

Seems that Tony has already done this, but I don't think that he asked
RT
to send his update to the list, and the default is not to​:

https://rt-archive.perl.org/perl5/Ticket/Display.html?id=115928#txn-1252961

It looks like clicking "Add More Files" removes the CC, which I didn't
notice.

Tony

I can confirm that is an RT bug. Also keeping javascript off leaves CC
empty when the page is loaded. So, there are 2 cases where CC becomes
empty accidentally and the RT post doesn't forward to ML. Here is a
question for thought, should it be possible to make a Perl RT post and
NOT have it forward to the ML? And should Perl RT be changed so
forwarding to the ML is unconditional?

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Sep 13, 2013

From @rjbs

* bulk88 via RT <perlbug-followup@​perl.org> [2013-09-12T21​:31​:33]

On Thu Sep 12 17​:58​:03 2013, tonyc wrote​:

It looks like clicking "Add More Files" removes the CC, which I didn't
notice.

I can confirm that is an RT bug.

I will get this passed along to our generous RT hosters. Thanks.

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Sep 13, 2013

From @tonycoz

On Thu Sep 12 07​:56​:27 2013, nicholas wrote​:

On Fri, Sep 06, 2013 at 01​:02​:03PM +0200, demerphq wrote​:

Thanks again for your work,

Ditto.

Applied as e7ab04c.

Tony

@p5pRT
Copy link
Author

p5pRT commented Sep 13, 2013

@tonycoz - Status changed from 'open' to 'resolved'

@p5pRT p5pRT closed this as completed Sep 13, 2013
@p5pRT
Copy link
Author

p5pRT commented Sep 16, 2013

From @Tux

On Thu, 12 Sep 2013 18​:57​:38 -0700, "Tony Cook via RT"
<perlbug-followup@​perl.org> wrote​:

On Thu Sep 12 07​:56​:27 2013, nicholas wrote​:

On Fri, Sep 06, 2013 at 01​:02​:03PM +0200, demerphq wrote​:

Thanks again for your work,

Ditto.

Applied as e7ab04c.

All of that backported to meta and regenerated into blead
thanks

--
H.Merijn Brand http​://tux.nl Perl Monger http​://amsterdam.pm.org/
using perl5.00307 .. 5.19 porting perl5 on HP-UX, AIX, and openSUSE
http​://mirrors.develooper.com/hpux/ http​://www.test-smoke.org/
http​://qa.perl.org http​://www.goldmark.org/jeff/stupid-disclaimers/

@p5pRT
Copy link
Author

p5pRT commented Sep 25, 2013

From p5p@jibsheet.com

On Thu, Sep 12, 2013 at 09​:47​:59PM -0400, Ricardo Signes wrote​:

* bulk88 via RT <perlbug-followup@​perl.org> [2013-09-12T21​:31​:33]

On Thu Sep 12 17​:58​:03 2013, tonyc wrote​:

It looks like clicking "Add More Files" removes the CC, which I didn't
notice.

I can confirm that is an RT bug.

I will get this passed along to our generous RT hosters. Thanks.

I've had a fix for this for a few days but finally had time to pull it
live on rt.perl.org.

-kevin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant