Commit b0c0d878 by Jonathan Wakely Committed by Jonathan Wakely

PR libstdc++/85494 use rdseed and rand_s in std::random_device

Add support for additional sources of randomness to std::random_device,
to allow using RDSEED for Intel CPUs and rand_s for Windows. When
supported these can be selected using the tokens "rdseed" and "rand_s".
For *-w64-mingw32 targets the "default" token will now use rand_s, and
for other i?86-*-* and x86_64-*-* targets it will try to use "rdseed"
first, then "rdrand", and finally "/dev/urandom".

To simplify the declaration of std::random_device in <bits/random.h> the
constructors now unconditionally call _M_init instead of _M_init_pretr1,
and the function call operator now unconditionally calls _M_getval. The
library code now decides whether _M_init and _M_getval should use a real
source of randomness or the mt19937 engine.

Existing code compiled against old libstdc++ headers will still call
_M_init_pretr1 and _M_getval_pretr1, but those functions now forward to
_M_init and _M_getval if a real source of randomness is available. This
means existing code compiled for mingw-w64 will start to use rand_s just
by linking to a new libstdc++.dll.

	* acinclude.m4 (GLIBCXX_CHECK_X86_RDSEED): Define macro to check if
	the assembler supports rdseed.
	* config.h.in: Regenerate.
	* configure: Regenerate.
	* configure.ac: Use GLIBCXX_CHECK_X86_RDSEED.
	* config/os/mingw32-w64/os_defines.h (_GLIBCXX_USE_CRT_RAND_S): Define.
	* doc/html/*: Regenerate.
	* doc/xml/manual/status_cxx2011.xml: Document new tokens.
	* include/bits/random.h (random_device::random_device()): Always call
	_M_init rather than _M_init_pretr1.
	(random_device::random_device(const string&)): Likewise.
	(random_device::operator()()): Always call _M_getval().
	(random_device::_M_file): Replace first member of union with an
	anonymous struct, with _M_file as its first member.
	* src/c++11/random.cc [_GLIBCXX_X86_RDRAND] (USE_RDRAND): Define.
	[_GLIBCXX_X86_RDSEED] (USE_RDSEED): Define.
	(USE_MT19937): Define if none of the above are defined.
	(USE_POSIX_FILE_IO): Define.
	(_M_strtoul): Remove.
	[USE_RDSEED] (__x86_rdseed): Define new function.
	[_GLIBCXX_USE_CRT_RAND_S] (__winxp_rand_s): Define new function.
	(random_device::_M_init(const string&)): Initialize new union members.
	Add support for "rdseed" and "rand_s" tokens. Decide what the
	"default" token does according to which USE_* macros are defined.
	[USE_POSIX_FILE_IO]: Store a file descriptor.
	[USE_MT19937]: Forward to _M_init_pretr1 instead.
	(random_device::_M_init_pretr1(const string&)) [USE_MT19937]: Inline
	code from _M_strtoul.
	[!USE_MT19937]: Call _M_init, transforming the old default token or
	numeric tokens to "default".
	(random_device::_M_fini()) [USE_POSIX_FILE_IO]: Use close not fclose.
	(random_device::_M_getval()): Use new union members to obtain a
	random number from the stored function pointer or file descriptor.
	[USE_MT19937]: Obtain a value from the mt19937 engine.
	(random_device::_M_getval_pretr1()): Call _M_getval().
	(random_device::_M_getentropy()) [USE_POSIX_FILE_IO]: Use _M_fd
	instead of fileno.
	[!USE_MT19937] (mersenne_twister): Do not instantiate when not needed.
	* testsuite/26_numerics/random/random_device/85494.cc: New test.

From-SVN: r271740
parent 0617e23c
2019-05-29 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/85494 use rdseed and rand_s in std::random_device
* acinclude.m4 (GLIBCXX_CHECK_X86_RDSEED): Define macro to check if
the assembler supports rdseed.
* config.h.in: Regenerate.
* configure: Regenerate.
* configure.ac: Use GLIBCXX_CHECK_X86_RDSEED.
* config/os/mingw32-w64/os_defines.h (_GLIBCXX_USE_CRT_RAND_S): Define.
* doc/html/*: Regenerate.
* doc/xml/manual/status_cxx2011.xml: Document new tokens.
* include/bits/random.h (random_device::random_device()): Always call
_M_init rather than _M_init_pretr1.
(random_device::random_device(const string&)): Likewise.
(random_device::operator()()): Always call _M_getval().
(random_device::_M_file): Replace first member of union with an
anonymous struct, with _M_file as its first member.
* src/c++11/random.cc [_GLIBCXX_X86_RDRAND] (USE_RDRAND): Define.
[_GLIBCXX_X86_RDSEED] (USE_RDSEED): Define.
(USE_MT19937): Define if none of the above are defined.
(USE_POSIX_FILE_IO): Define.
(_M_strtoul): Remove.
[USE_RDSEED] (__x86_rdseed): Define new function.
[_GLIBCXX_USE_CRT_RAND_S] (__winxp_rand_s): Define new function.
(random_device::_M_init(const string&)): Initialize new union members.
Add support for "rdseed" and "rand_s" tokens. Decide what the
"default" token does according to which USE_* macros are defined.
[USE_POSIX_FILE_IO]: Store a file descriptor.
[USE_MT19937]: Forward to _M_init_pretr1 instead.
(random_device::_M_init_pretr1(const string&)) [USE_MT19937]: Inline
code from _M_strtoul.
[!USE_MT19937]: Call _M_init, transforming the old default token or
numeric tokens to "default".
(random_device::_M_fini()) [USE_POSIX_FILE_IO]: Use close not fclose.
(random_device::_M_getval()): Use new union members to obtain a
random number from the stored function pointer or file descriptor.
[USE_MT19937]: Obtain a value from the mt19937 engine.
(random_device::_M_getval_pretr1()): Call _M_getval().
(random_device::_M_getentropy()) [USE_POSIX_FILE_IO]: Use _M_fd
instead of fileno.
[!USE_MT19937] (mersenne_twister): Do not instantiate when not needed.
* testsuite/26_numerics/random/random_device/85494.cc: New test.
2019-05-28 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/90634
......
......@@ -4054,6 +4054,26 @@ AC_DEFUN([GLIBCXX_CHECK_X86_RDRAND], [
])
dnl
dnl Check whether rdseed is supported in the assembler.
AC_DEFUN([GLIBCXX_CHECK_X86_RDSEED], [
AC_MSG_CHECKING([for rdseed support in assembler])
AC_CACHE_VAL(ac_cv_x86_rdseed, [
ac_cv_x86_rdseed=no
case "$target" in
i?86-*-* | \
x86_64-*-*)
AC_TRY_COMPILE(, [asm("rdseed %eax");],
[ac_cv_x86_rdseed=yes], [ac_cv_x86_rdseed=no])
esac
])
if test $ac_cv_x86_rdseed = yes; then
AC_DEFINE(_GLIBCXX_X86_RDSEED, 1,
[ Defined if as can handle rdseed. ])
fi
AC_MSG_RESULT($ac_cv_x86_rdseed)
])
dnl
dnl Check whether get_nprocs is available in <sys/sysinfo.h>, and define _GLIBCXX_USE_GET_NPROCS.
dnl
AC_DEFUN([GLIBCXX_CHECK_GET_NPROCS], [
......
......@@ -1038,6 +1038,9 @@
/* Defined if as can handle rdrand. */
#undef _GLIBCXX_X86_RDRAND
/* Defined if as can handle rdseed. */
#undef _GLIBCXX_X86_RDSEED
/* Define to 1 if mutex_timedlock is available. */
#undef _GTHREAD_USE_MUTEX_TIMEDLOCK
......
......@@ -88,4 +88,6 @@
// See libstdc++/59807
#define _GTHREAD_USE_MUTEX_INIT_FUNC 1
#define _GLIBCXX_USE_CRT_RAND_S 1
#endif
......@@ -79870,6 +79870,47 @@ $as_echo "#define _GLIBCXX_X86_RDRAND 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_x86_rdrand" >&5
$as_echo "$ac_cv_x86_rdrand" >&6; }
# Check if assembler supports rdseed opcode.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for rdseed support in assembler" >&5
$as_echo_n "checking for rdseed support in assembler... " >&6; }
if test "${ac_cv_x86_rdseed+set}" = set; then :
$as_echo_n "(cached) " >&6
else
ac_cv_x86_rdseed=no
case "$target" in
i?86-*-* | \
x86_64-*-*)
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
asm("rdseed %eax");
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_x86_rdseed=yes
else
ac_cv_x86_rdseed=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
esac
fi
if test $ac_cv_x86_rdseed = yes; then
$as_echo "#define _GLIBCXX_X86_RDSEED 1" >>confdefs.h
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_x86_rdseed" >&5
$as_echo "$ac_cv_x86_rdseed" >&6; }
# This depends on GLIBCXX_ENABLE_SYMVERS and GLIBCXX_IS_NATIVE.
......@@ -417,6 +417,8 @@ GCC_CHECK_ASSEMBLER_HWCAP
# Check if assembler supports rdrand opcode.
GLIBCXX_CHECK_X86_RDRAND
# Check if assembler supports rdseed opcode.
GLIBCXX_CHECK_X86_RDSEED
# This depends on GLIBCXX_ENABLE_SYMVERS and GLIBCXX_IS_NATIVE.
GLIBCXX_CONFIGURE_TESTSUITE
......
......@@ -26,7 +26,7 @@
organization. In the USA, this national standards
organization is
<a class="link" href="https://www.ansi.org" target="_top">ANSI</a>.
(And if you've already registered with them you can <a class="link" href="https://webstore.ansi.org/RecordDetail.aspx?sku=ISO%2fIEC+14882%3a2014" target="_top">buy
(And if you've already registered with them you can <a class="link" href="https://webstore.ansi.org/Standards/ISO/ISOIEC148822014" target="_top">buy
the standard on-line</a>.)
</p></li><li class="listitem"><p>
The library working group bugs, and known defects, can
......
......@@ -303,18 +303,38 @@ particular release.
<code class="classname">minstd_rand0</code>.
</p><p>
<span class="emphasis"><em> 26.5.6 [rand.device] </em></span>
The default <code class="code">token</code> argument to the
<code class="classname">random_device</code> constructor is
<code class="literal">"default"</code>. Other valid arguments are
<code class="literal">"/dev/random"</code> and <code class="literal">"/dev/urandom"</code>,
which determine the character special file to read random bytes from.
The <code class="literal">"default"</code> token will read bytes from a hardware
RNG if available (currently this only supports the IA-32 RDRAND
instruction) otherwise it is equivalent to
<code class="literal">"/dev/urandom"</code>.
The <code class="code">token</code> parameter of the
<code class="classname">random_device</code> constructor can be used to select
a specific source of random bytes. The valid token values are shown
in the list below.
The default constructor uses the token <code class="literal">"default"</code>.
</p><div class="variablelist"><dl class="variablelist"><dt><span class="term"><code class="literal">"default"</code></span></dt><dd>
Select the first available source from the other entries below.
This is the only token that is always valid.
</dd><dt><span class="term"><code class="literal">"rand_s"</code></span></dt><dd>
Use the MSVCRT <code class="function">rand_s</code> function.
This token is only valid for mingw-w64 targets.
</dd><dt><span class="term"><code class="literal">"rdseed"</code>, </span><span class="term"><code class="literal">"rdrand"</code> or <code class="literal">"rdrnd"</code></span></dt><dd>
Use the IA-32 <code class="literal">RDSEED</code> or <code class="literal">RDRAND</code>
instruction to read from an on-chip hardware random number generator.
These tokens are only valid for x86 and x86_64 targets when both
the assembler and CPU support the corresponding instruction.
</dd><dt><span class="term"><code class="literal">"/dev/urandom"</code>, </span><span class="term"><code class="literal">"/dev/random"</code></span></dt><dd>
Use the named character special file to read random bytes from.
These tokens are only valid when the device files are present
and readable by the current user.
</dd><dt><span class="term"><code class="literal">"mt19937"</code>, </span><span class="term">seed value</span></dt><dd>
When no source of nondeterministic random numbers is available a
<code class="classname">mersenne_twister_engine</code> will be used.
An integer seed value can be used as the token and will be converted
to an <code class="code">unsigned long</code> using <code class="function">strtoul</code>.
These tokens are only valid when no other source of random bytes
is available.
</dd></dl></div><p>
An exception of type <code class="classname">runtime_error</code> will be
thrown if a <code class="classname">random_device</code> object cannot open
or read from the source of random bytes.
thrown if a <code class="classname">random_device</code> object is constructed
with an invalid token, or if it cannot open or read from the source
of random bytes.
</p><p>
<span class="emphasis"><em>26.5.8.1 [rand.dist.general]</em></span>
The algorithms used by the distributions should be documented here.
......
......@@ -2682,18 +2682,62 @@ particular release.
<para>
<emphasis> 26.5.6 [rand.device] </emphasis>
The default <code>token</code> argument to the
<classname>random_device</classname> constructor is
<literal>"default"</literal>. Other valid arguments are
<literal>"/dev/random"</literal> and <literal>"/dev/urandom"</literal>,
which determine the character special file to read random bytes from.
The <literal>"default"</literal> token will read bytes from a hardware
RNG if available (currently this only supports the IA-32 RDRAND
instruction) otherwise it is equivalent to
<literal>"/dev/urandom"</literal>.
The <code>token</code> parameter of the
<classname>random_device</classname> constructor can be used to select
a specific source of random bytes. The valid token values are shown
in the list below.
The default constructor uses the token <literal>"default"</literal>.
<variablelist>
<varlistentry>
<term><literal>"default"</literal></term>
<listitem>
Select the first available source from the other entries below.
This is the only token that is always valid.
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"rand_s"</literal></term>
<listitem>
Use the MSVCRT <function>rand_s</function> function.
This token is only valid for mingw-w64 targets.
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"rdseed"</literal></term>
<term><literal>"rdrand"</literal> or <literal>"rdrnd"</literal></term>
<listitem>
Use the IA-32 <literal>RDSEED</literal> or <literal>RDRAND</literal>
instruction to read from an on-chip hardware random number generator.
These tokens are only valid for x86 and x86_64 targets when both
the assembler and CPU support the corresponding instruction.
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"/dev/urandom"</literal></term>
<term><literal>"/dev/random"</literal></term>
<listitem>
Use the named character special file to read random bytes from.
These tokens are only valid when the device files are present
and readable by the current user.
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"mt19937"</literal></term>
<term>seed value</term>
<listitem>
When no source of nondeterministic random numbers is available a
<classname>mersenne_twister_engine</classname> will be used.
An integer seed value can be used as the token and will be converted
to an <code>unsigned long</code> using <function>strtoul</function>.
These tokens are only valid when no other source of random bytes
is available.
</listitem>
</varlistentry>
</variablelist>
An exception of type <classname>runtime_error</classname> will be
thrown if a <classname>random_device</classname> object cannot open
or read from the source of random bytes.
thrown if a <classname>random_device</classname> object is constructed
with an invalid token, or if it cannot open or read from the source
of random bytes.
</para>
<para>
......
......@@ -1602,20 +1602,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// constructors, destructors and member functions
#ifdef _GLIBCXX_USE_DEV_RANDOM
random_device() { _M_init("default"); }
explicit
random_device(const std::string& __token) { _M_init(__token); }
#if defined _GLIBCXX_USE_DEV_RANDOM
~random_device()
{ _M_fini(); }
#else
random_device() { _M_init_pretr1("mt19937"); }
explicit
random_device(const std::string& __token)
{ _M_init_pretr1(__token); }
#endif
static constexpr result_type
......@@ -1638,13 +1632,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
result_type
operator()()
{
#ifdef _GLIBCXX_USE_DEV_RANDOM
return this->_M_getval();
#else
return this->_M_getval_pretr1();
#endif
}
{ return this->_M_getval(); }
// No copy functions.
random_device(const random_device&) = delete;
......@@ -1662,7 +1650,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
union
{
void* _M_file;
struct
{
void* _M_file;
result_type (*_M_func)(void*);
int _M_fd;
};
mt19937 _M_mt;
};
};
......
// Copyright (C) 2019 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-do run { target c++11 } }
// { dg-require-effective-target random_device }
#include <random>
#include <testsuite_hooks.h>
void
test01()
{
unsigned v1[3], v2[3];
std::random_device d1, d2;
for (auto& v : v1)
v = d1();
for (auto& v : v2)
v = d2();
VERIFY (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] );
}
int
main()
{
test01();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment