diff mbox series

[committed] libstdc++: Support getentropy and arc4random in std::random_device

Message ID 20211105182023.2257591-1-jwakely@redhat.com
State New
Headers show
Series [committed] libstdc++: Support getentropy and arc4random in std::random_device | expand

Commit Message

Jonathan Wakely Nov. 5, 2021, 6:20 p.m. UTC
This adds additional "getentropy" and "arc4random" tokens to
std::random_device. The former is supported on Glibc and OpenBSD (and
apparently wasm), and the latter is supported on various BSDs.

I'm trying to test this on OpenBSD but I can't bootstrap GCC using the
system clang.


libstdc++-v3/ChangeLog:

	* acinclude.m4 (GLIBCXX_CHECK_GETENTROPY, GLIBCXX_CHECK_ARC4RANDOM):
	Define.
	* configure.ac (GLIBCXX_CHECK_GETENTROPY, GLIBCXX_CHECK_ARC4RANDOM):
	Use them.
	* config.h.in: Regenerate.
	* configure: Regenerate.
	* src/c++11/random.cc (random_device): Add getentropy and
	arc4random as sources.
	* testsuite/26_numerics/random/random_device/cons/token.cc:
	Check new tokens.
	* testsuite/26_numerics/random/random_device/entropy.cc:
	Likewise.
---
 libstdc++-v3/acinclude.m4                     |  46 ++++++++
 libstdc++-v3/config.h.in                      |   6 +
 libstdc++-v3/configure                        | 103 ++++++++++++++++++
 libstdc++-v3/configure.ac                     |   4 +
 libstdc++-v3/src/c++11/random.cc              |  69 +++++++++++-
 .../random/random_device/cons/token.cc        |   1 +
 .../random/random_device/entropy.cc           |   7 ++
 7 files changed, 234 insertions(+), 2 deletions(-)

Comments

Jonathan Wakely Nov. 5, 2021, 6:22 p.m. UTC | #1
Oops sorry - this is NOT committed yet. I won't push it until I've tested
it on at least one BSD, preferably OpenBSD so I can test parts of the new
code.


On Fri, 5 Nov 2021 at 18:21, Jonathan Wakely via Libstdc++ <
libstdc++@gcc.gnu.org> wrote:

> This adds additional "getentropy" and "arc4random" tokens to
> std::random_device. The former is supported on Glibc and OpenBSD (and
> apparently wasm), and the latter is supported on various BSDs.
>
> I'm trying to test this on OpenBSD but I can't bootstrap GCC using the
> system clang.
>
>
> libstdc++-v3/ChangeLog:
>
>         * acinclude.m4 (GLIBCXX_CHECK_GETENTROPY,
> GLIBCXX_CHECK_ARC4RANDOM):
>         Define.
>         * configure.ac (GLIBCXX_CHECK_GETENTROPY,
> GLIBCXX_CHECK_ARC4RANDOM):
>         Use them.
>         * config.h.in: Regenerate.
>         * configure: Regenerate.
>         * src/c++11/random.cc (random_device): Add getentropy and
>         arc4random as sources.
>         * testsuite/26_numerics/random/random_device/cons/token.cc:
>         Check new tokens.
>         * testsuite/26_numerics/random/random_device/entropy.cc:
>         Likewise.
> ---
>  libstdc++-v3/acinclude.m4                     |  46 ++++++++
>  libstdc++-v3/config.h.in                      |   6 +
>  libstdc++-v3/configure                        | 103 ++++++++++++++++++
>  libstdc++-v3/configure.ac                     |   4 +
>  libstdc++-v3/src/c++11/random.cc              |  69 +++++++++++-
>  .../random/random_device/cons/token.cc        |   1 +
>  .../random/random_device/entropy.cc           |   7 ++
>  7 files changed, 234 insertions(+), 2 deletions(-)
>
> diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
> index 90ecc4a87a2..497af5723e1 100644
> --- a/libstdc++-v3/acinclude.m4
> +++ b/libstdc++-v3/acinclude.m4
> @@ -4830,6 +4830,52 @@ AC_DEFUN([GLIBCXX_CHECK_EXCEPTION_PTR_SYMVER], [
>    fi
>  ])
>
> +dnl
> +dnl Check whether getentropy is present in <unistd.h>.
> +dnl
> +AC_DEFUN([GLIBCXX_CHECK_GETENTROPY], [
> +
> +  AC_LANG_SAVE
> +  AC_LANG_CPLUSPLUS
> +  AC_MSG_CHECKING([for getentropy])
> +  AC_CACHE_VAL(glibcxx_cv_getentropy, [
> +      AC_TRY_COMPILE(
> +       [#include <unistd.h>],
> +       [unsigned i;
> +        ::getentropy(&i, sizeof(i));],
> +       [glibcxx_cv_getentropy=yes], [glibcxx_cv_getentropy=no])
> +    ])
> +
> +  if test $glibcxx_cv_getentropy = yes; then
> +    AC_DEFINE(HAVE_GETENTROPY, 1, [Define if getentropy is available in
> <unistd.h>.])
> +  fi
> +  AC_MSG_RESULT($glibcxx_cv_getentropy)
> +  AC_LANG_RESTORE
> +])
> +
> +dnl
> +dnl Check whether arc4random is present in <stdlib.h>.
> +dnl
> +AC_DEFUN([GLIBCXX_CHECK_ARC4RANDOM], [
> +
> +  AC_LANG_SAVE
> +  AC_LANG_CPLUSPLUS
> +  AC_MSG_CHECKING([for arc4random])
> +  AC_CACHE_VAL(glibcxx_cv_arc4random, [
> +      AC_TRY_COMPILE(
> +       [#include <stdlib.h>],
> +       [unsigned i = ::arc4random();],
> +       [glibcxx_cv_arc4random=yes], [glibcxx_cv_arc4random=no])
> +    ])
> +
> +  if test $glibcxx_cv_arc4random = yes; then
> +    AC_DEFINE(HAVE_ARC4RANDOM, 1, [Define if arc4random is available in
> <stdlib.h>.])
> +  fi
> +  AC_MSG_RESULT($glibcxx_cv_arc4random)
> +  AC_LANG_RESTORE
> +])
> +
> +
>  # Macros from the top-level gcc directory.
>  m4_include([../config/gc++filt.m4])
>  m4_include([../config/tls.m4])
> diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in
> index 228a758325e..420021fcb1a 100644
> --- a/libstdc++-v3/config.h.in
> +++ b/libstdc++-v3/config.h.in
> @@ -9,6 +9,9 @@
>  /* Define to 1 if you have the `aligned_alloc' function. */
>  #undef HAVE_ALIGNED_ALLOC
>
> +/* Define if arc4random is available in <stdlib.h>. */
> +#undef HAVE_ARC4RANDOM
> +
>  /* Define to 1 if you have the <arpa/inet.h> header file. */
>  #undef HAVE_ARPA_INET_H
>
> @@ -132,6 +135,9 @@
>  /* Define to 1 if you have the `frexpl' function. */
>  #undef HAVE_FREXPL
>
> +/* Define if getentropy is available in <unistd.h>. */
> +#undef HAVE_GETENTROPY
> +
>  /* Define if _Unwind_GetIPInfo is available. */
>  #undef HAVE_GETIPINFO
>
> diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
> index c1aea827070..21371031b66 100755
> --- a/libstdc++-v3/configure
> +++ b/libstdc++-v3/configure
> @@ -75429,6 +75429,109 @@ $as_echo "#define _GLIBCXX_X86_RDSEED 1"
> >>confdefs.h
>  $as_echo "$ac_cv_x86_rdseed" >&6; }
>
>
> +# Check for other random number APIs
> +
> +
> +
> +  ac_ext=cpp
> +ac_cpp='$CXXCPP $CPPFLAGS'
> +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
> +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS
> conftest.$ac_ext $LIBS >&5'
> +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
> +
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getentropy" >&5
> +$as_echo_n "checking for getentropy... " >&6; }
> +  if ${glibcxx_cv_getentropy+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +
> +      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> +/* end confdefs.h.  */
> +#include <unistd.h>
> +int
> +main ()
> +{
> +unsigned i;
> +        ::getentropy(&i, sizeof(i));
> +  ;
> +  return 0;
> +}
> +_ACEOF
> +if ac_fn_cxx_try_compile "$LINENO"; then :
> +  glibcxx_cv_getentropy=yes
> +else
> +  glibcxx_cv_getentropy=no
> +fi
> +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
> +
> +fi
> +
> +
> +  if test $glibcxx_cv_getentropy = yes; then
> +
> +$as_echo "#define HAVE_GETENTROPY 1" >>confdefs.h
> +
> +  fi
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result:
> $glibcxx_cv_getentropy" >&5
> +$as_echo "$glibcxx_cv_getentropy" >&6; }
> +  ac_ext=c
> +ac_cpp='$CPP $CPPFLAGS'
> +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
> +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS
> conftest.$ac_ext $LIBS >&5'
> +ac_compiler_gnu=$ac_cv_c_compiler_gnu
> +
> +
> +
> +
> +
> +  ac_ext=cpp
> +ac_cpp='$CXXCPP $CPPFLAGS'
> +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
> +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS
> conftest.$ac_ext $LIBS >&5'
> +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
> +
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for arc4random" >&5
> +$as_echo_n "checking for arc4random... " >&6; }
> +  if ${glibcxx_cv_arc4random+:} false; then :
> +  $as_echo_n "(cached) " >&6
> +else
> +
> +      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> +/* end confdefs.h.  */
> +#include <stdlib.h>
> +int
> +main ()
> +{
> +unsigned i = ::arc4random();
> +  ;
> +  return 0;
> +}
> +_ACEOF
> +if ac_fn_cxx_try_compile "$LINENO"; then :
> +  glibcxx_cv_arc4random=yes
> +else
> +  glibcxx_cv_arc4random=no
> +fi
> +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
> +
> +fi
> +
> +
> +  if test $glibcxx_cv_arc4random = yes; then
> +
> +$as_echo "#define HAVE_ARC4RANDOM 1" >>confdefs.h
> +
> +  fi
> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result:
> $glibcxx_cv_arc4random" >&5
> +$as_echo "$glibcxx_cv_arc4random" >&6; }
> +  ac_ext=c
> +ac_cpp='$CPP $CPPFLAGS'
> +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
> +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS
> conftest.$ac_ext $LIBS >&5'
> +ac_compiler_gnu=$ac_cv_c_compiler_gnu
> +
> +
> +
>  # This depends on GLIBCXX_ENABLE_SYMVERS and GLIBCXX_IS_NATIVE.
>
>    # Do checks for resource limit functions.
> diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
> index 2d68b3672b9..5b3c92f4bd7 100644
> --- a/libstdc++-v3/configure.ac
> +++ b/libstdc++-v3/configure.ac
> @@ -468,6 +468,10 @@ GLIBCXX_CHECK_X86_RDRAND
>  # Check if assembler supports rdseed opcode.
>  GLIBCXX_CHECK_X86_RDSEED
>
> +# Check for other random number APIs
> +GLIBCXX_CHECK_GETENTROPY
> +GLIBCXX_CHECK_ARC4RANDOM
> +
>  # This depends on GLIBCXX_ENABLE_SYMVERS and GLIBCXX_IS_NATIVE.
>  GLIBCXX_CONFIGURE_TESTSUITE
>
> diff --git a/libstdc++-v3/src/c++11/random.cc
> b/libstdc++-v3/src/c++11/random.cc
> index 4b88818646f..4a553e0d84f 100644
> --- a/libstdc++-v3/src/c++11/random.cc
> +++ b/libstdc++-v3/src/c++11/random.cc
> @@ -68,7 +68,12 @@
>  # include <stdlib.h>
>  #endif
>
> -#if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM
> +#ifdef _GLIBCXX_HAVE_GETENTROPY
> +# include <unistd.h>
> +#endif
> +
> +#if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM \
> +  || _GLIBCXX_HAVE_GETENTROPY
>  // The OS provides a source of randomness we can use.
>  # pragma GCC poison _M_mt
>  #elif defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
> @@ -166,6 +171,25 @@ namespace std _GLIBCXX_VISIBILITY(default)
>      }
>  #endif
>
> +#ifdef _GLIBCXX_HAVE_GETENTROPY
> +    unsigned int
> +    __libc_getentropy(void*)
> +    {
> +      unsigned int val;
> +      if (::getentropy(&val, sizeof(val)) != 0)
> +       std::__throw_runtime_error(__N("random_device: getentropy
> failed"));
> +      return val;
> +    }
> +#endif
> +
> +#ifdef _GLIBCXX_HAVE_ARC4RANDOM
> +    unsigned int
> +    __libc_arc4random(void*)
> +    {
> +      return ::arc4random();
> +    }
> +#endif
> +
>  #ifdef USE_LCG
>      // TODO: use this to seed std::mt19937 engine too.
>      unsigned
> @@ -214,7 +238,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
>  #endif
>
>      enum Which : unsigned {
> -      device_file = 1, prng = 2, rand_s = 4,
> +      device_file = 1, prng = 2, rand_s = 4, getentropy = 8, arc4random =
> 16,
>        rdseed = 64, rdrand = 128, darn = 256,
>        any = 0xffff
>      };
> @@ -256,6 +280,16 @@ namespace std _GLIBCXX_VISIBILITY(default)
>         return device_file;
>  #endif
>
> +#ifdef _GLIBCXX_HAVE_ARC4RANDOM
> +      if (func == __libc_arc4random)
> +       return arc4random;
> +#endif
> +
> +#ifdef _GLIBCXX_HAVE_GETENTROPY
> +      if (func == __libc_getentropy)
> +       return getentropy;
> +#endif
> +
>  #ifdef USE_LCG
>        if (func == &__lcg)
>         return prng;
> @@ -311,6 +345,14 @@ namespace std _GLIBCXX_VISIBILITY(default)
>      else if (token == "rand_s")
>        which = rand_s;
>  #endif // _GLIBCXX_USE_CRT_RAND_S
> +#ifdef _GLIBCXX_HAVE_GETENTROPY
> +    else if (token == "getentropy")
> +      which = getentropy;
> +#endif // _GLIBCXX_HAVE_GETENTROPY
> +#ifdef _GLIBCXX_HAVE_ARC4RANDOM
> +    else if (token == "arc4random")
> +      which = arc4random;
> +#endif // _GLIBCXX_HAVE_ARC4RANDOM
>  #ifdef _GLIBCXX_USE_DEV_RANDOM
>      else if (token == "/dev/urandom" || token == "/dev/random")
>        {
> @@ -395,6 +437,26 @@ namespace std _GLIBCXX_VISIBILITY(default)
>        }
>  #endif // USE_DARN
>
> +#ifdef _GLIBCXX_HAVE_ARC4RANDOM
> +    if (which & arc4random)
> +      {
> +       _M_func = &__libc_arc4random;
> +       return;
> +      }
> +#endif // _GLIBCXX_HAVE_ARC4RANDOM
> +
> +#ifdef _GLIBCXX_HAVE_GETENTROPY
> +    if (which & getentropy)
> +      {
> +       unsigned int i;
> +       if (::getentropy(&i, sizeof(i)) == 0) // On linux the syscall can
> fail.
> +         {
> +           _M_func = &__libc_getentropy;
> +           return;
> +         }
> +      }
> +#endif // _GLIBCXX_HAVE_GETENTROPY
> +
>  #ifdef _GLIBCXX_USE_DEV_RANDOM
>      if (which & device_file)
>      {
> @@ -548,6 +610,9 @@ namespace std _GLIBCXX_VISIBILITY(default)
>      case rdseed:
>      case darn:
>        return (double) max;
> +    case arc4random:
> +    case getentropy:
> +      return (double) max;
>      case rand_s:
>      case prng:
>        return 0.0;
> diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
> b/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
> index d6ac3a37c64..e13484e03a5 100644
> --- a/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
> +++ b/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
> @@ -53,6 +53,7 @@ test03()
>    const std::string tokens[] = {
>      "rdseed", "rdrand", "darn",
>      "rand_s", "/dev/urandom", "/dev/random",
> +    "getentropy", "arc4random",
>      "mt19937", "prng"
>    };
>    int count = 0;
> diff --git
> a/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
> b/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
> index 6f3ebb1b38e..63b7043bf9b 100644
> --- a/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
> +++ b/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
> @@ -28,6 +28,13 @@ test01()
>        const double entropy = std::random_device(token).entropy();
>        VERIFY( entropy == max );
>      }
> +
> +    for (auto token : { "getentropy", "arc4random" })
> +    if (__gnu_test::random_device_available(token))
> +    {
> +      const double entropy = std::random_device(token).entropy();
> +      VERIFY( entropy == max );
> +    }
>  }
>
>  int
> --
> 2.31.1
>
>
Jonathan Wakely Nov. 9, 2021, 3:17 p.m. UTC | #2
On Fri, 5 Nov 2021 at 18:22, Jonathan Wakely wrote:

> Oops sorry - this is NOT committed yet. I won't push it until I've tested
> it on at least one BSD, preferably OpenBSD so I can test parts of the new
> code.
>

It got tested on darwin, and has been pushed to trunk now.



>
>
> On Fri, 5 Nov 2021 at 18:21, Jonathan Wakely via Libstdc++ <
> libstdc++@gcc.gnu.org> wrote:
>
>> This adds additional "getentropy" and "arc4random" tokens to
>> std::random_device. The former is supported on Glibc and OpenBSD (and
>> apparently wasm), and the latter is supported on various BSDs.
>>
>> I'm trying to test this on OpenBSD but I can't bootstrap GCC using the
>> system clang.
>>
>>
>> libstdc++-v3/ChangeLog:
>>
>>         * acinclude.m4 (GLIBCXX_CHECK_GETENTROPY,
>> GLIBCXX_CHECK_ARC4RANDOM):
>>         Define.
>>         * configure.ac (GLIBCXX_CHECK_GETENTROPY,
>> GLIBCXX_CHECK_ARC4RANDOM):
>>         Use them.
>>         * config.h.in: Regenerate.
>>         * configure: Regenerate.
>>         * src/c++11/random.cc (random_device): Add getentropy and
>>         arc4random as sources.
>>         * testsuite/26_numerics/random/random_device/cons/token.cc:
>>         Check new tokens.
>>         * testsuite/26_numerics/random/random_device/entropy.cc:
>>         Likewise.
>> ---
>>  libstdc++-v3/acinclude.m4                     |  46 ++++++++
>>  libstdc++-v3/config.h.in                      |   6 +
>>  libstdc++-v3/configure                        | 103 ++++++++++++++++++
>>  libstdc++-v3/configure.ac                     |   4 +
>>  libstdc++-v3/src/c++11/random.cc              |  69 +++++++++++-
>>  .../random/random_device/cons/token.cc        |   1 +
>>  .../random/random_device/entropy.cc           |   7 ++
>>  7 files changed, 234 insertions(+), 2 deletions(-)
>>
>> diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
>> index 90ecc4a87a2..497af5723e1 100644
>> --- a/libstdc++-v3/acinclude.m4
>> +++ b/libstdc++-v3/acinclude.m4
>> @@ -4830,6 +4830,52 @@ AC_DEFUN([GLIBCXX_CHECK_EXCEPTION_PTR_SYMVER], [
>>    fi
>>  ])
>>
>> +dnl
>> +dnl Check whether getentropy is present in <unistd.h>.
>> +dnl
>> +AC_DEFUN([GLIBCXX_CHECK_GETENTROPY], [
>> +
>> +  AC_LANG_SAVE
>> +  AC_LANG_CPLUSPLUS
>> +  AC_MSG_CHECKING([for getentropy])
>> +  AC_CACHE_VAL(glibcxx_cv_getentropy, [
>> +      AC_TRY_COMPILE(
>> +       [#include <unistd.h>],
>> +       [unsigned i;
>> +        ::getentropy(&i, sizeof(i));],
>> +       [glibcxx_cv_getentropy=yes], [glibcxx_cv_getentropy=no])
>> +    ])
>> +
>> +  if test $glibcxx_cv_getentropy = yes; then
>> +    AC_DEFINE(HAVE_GETENTROPY, 1, [Define if getentropy is available in
>> <unistd.h>.])
>> +  fi
>> +  AC_MSG_RESULT($glibcxx_cv_getentropy)
>> +  AC_LANG_RESTORE
>> +])
>> +
>> +dnl
>> +dnl Check whether arc4random is present in <stdlib.h>.
>> +dnl
>> +AC_DEFUN([GLIBCXX_CHECK_ARC4RANDOM], [
>> +
>> +  AC_LANG_SAVE
>> +  AC_LANG_CPLUSPLUS
>> +  AC_MSG_CHECKING([for arc4random])
>> +  AC_CACHE_VAL(glibcxx_cv_arc4random, [
>> +      AC_TRY_COMPILE(
>> +       [#include <stdlib.h>],
>> +       [unsigned i = ::arc4random();],
>> +       [glibcxx_cv_arc4random=yes], [glibcxx_cv_arc4random=no])
>> +    ])
>> +
>> +  if test $glibcxx_cv_arc4random = yes; then
>> +    AC_DEFINE(HAVE_ARC4RANDOM, 1, [Define if arc4random is available in
>> <stdlib.h>.])
>> +  fi
>> +  AC_MSG_RESULT($glibcxx_cv_arc4random)
>> +  AC_LANG_RESTORE
>> +])
>> +
>> +
>>  # Macros from the top-level gcc directory.
>>  m4_include([../config/gc++filt.m4])
>>  m4_include([../config/tls.m4])
>> diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in
>> index 228a758325e..420021fcb1a 100644
>> --- a/libstdc++-v3/config.h.in
>> +++ b/libstdc++-v3/config.h.in
>> @@ -9,6 +9,9 @@
>>  /* Define to 1 if you have the `aligned_alloc' function. */
>>  #undef HAVE_ALIGNED_ALLOC
>>
>> +/* Define if arc4random is available in <stdlib.h>. */
>> +#undef HAVE_ARC4RANDOM
>> +
>>  /* Define to 1 if you have the <arpa/inet.h> header file. */
>>  #undef HAVE_ARPA_INET_H
>>
>> @@ -132,6 +135,9 @@
>>  /* Define to 1 if you have the `frexpl' function. */
>>  #undef HAVE_FREXPL
>>
>> +/* Define if getentropy is available in <unistd.h>. */
>> +#undef HAVE_GETENTROPY
>> +
>>  /* Define if _Unwind_GetIPInfo is available. */
>>  #undef HAVE_GETIPINFO
>>
>> diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
>> index c1aea827070..21371031b66 100755
>> --- a/libstdc++-v3/configure
>> +++ b/libstdc++-v3/configure
>> @@ -75429,6 +75429,109 @@ $as_echo "#define _GLIBCXX_X86_RDSEED 1"
>> >>confdefs.h
>>  $as_echo "$ac_cv_x86_rdseed" >&6; }
>>
>>
>> +# Check for other random number APIs
>> +
>> +
>> +
>> +  ac_ext=cpp
>> +ac_cpp='$CXXCPP $CPPFLAGS'
>> +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
>> +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS
>> conftest.$ac_ext $LIBS >&5'
>> +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
>> +
>> +  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getentropy" >&5
>> +$as_echo_n "checking for getentropy... " >&6; }
>> +  if ${glibcxx_cv_getentropy+:} false; then :
>> +  $as_echo_n "(cached) " >&6
>> +else
>> +
>> +      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
>> +/* end confdefs.h.  */
>> +#include <unistd.h>
>> +int
>> +main ()
>> +{
>> +unsigned i;
>> +        ::getentropy(&i, sizeof(i));
>> +  ;
>> +  return 0;
>> +}
>> +_ACEOF
>> +if ac_fn_cxx_try_compile "$LINENO"; then :
>> +  glibcxx_cv_getentropy=yes
>> +else
>> +  glibcxx_cv_getentropy=no
>> +fi
>> +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
>> +
>> +fi
>> +
>> +
>> +  if test $glibcxx_cv_getentropy = yes; then
>> +
>> +$as_echo "#define HAVE_GETENTROPY 1" >>confdefs.h
>> +
>> +  fi
>> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result:
>> $glibcxx_cv_getentropy" >&5
>> +$as_echo "$glibcxx_cv_getentropy" >&6; }
>> +  ac_ext=c
>> +ac_cpp='$CPP $CPPFLAGS'
>> +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
>> +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS
>> conftest.$ac_ext $LIBS >&5'
>> +ac_compiler_gnu=$ac_cv_c_compiler_gnu
>> +
>> +
>> +
>> +
>> +
>> +  ac_ext=cpp
>> +ac_cpp='$CXXCPP $CPPFLAGS'
>> +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
>> +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS
>> conftest.$ac_ext $LIBS >&5'
>> +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
>> +
>> +  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for arc4random" >&5
>> +$as_echo_n "checking for arc4random... " >&6; }
>> +  if ${glibcxx_cv_arc4random+:} false; then :
>> +  $as_echo_n "(cached) " >&6
>> +else
>> +
>> +      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
>> +/* end confdefs.h.  */
>> +#include <stdlib.h>
>> +int
>> +main ()
>> +{
>> +unsigned i = ::arc4random();
>> +  ;
>> +  return 0;
>> +}
>> +_ACEOF
>> +if ac_fn_cxx_try_compile "$LINENO"; then :
>> +  glibcxx_cv_arc4random=yes
>> +else
>> +  glibcxx_cv_arc4random=no
>> +fi
>> +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
>> +
>> +fi
>> +
>> +
>> +  if test $glibcxx_cv_arc4random = yes; then
>> +
>> +$as_echo "#define HAVE_ARC4RANDOM 1" >>confdefs.h
>> +
>> +  fi
>> +  { $as_echo "$as_me:${as_lineno-$LINENO}: result:
>> $glibcxx_cv_arc4random" >&5
>> +$as_echo "$glibcxx_cv_arc4random" >&6; }
>> +  ac_ext=c
>> +ac_cpp='$CPP $CPPFLAGS'
>> +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
>> +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS
>> conftest.$ac_ext $LIBS >&5'
>> +ac_compiler_gnu=$ac_cv_c_compiler_gnu
>> +
>> +
>> +
>>  # This depends on GLIBCXX_ENABLE_SYMVERS and GLIBCXX_IS_NATIVE.
>>
>>    # Do checks for resource limit functions.
>> diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
>> index 2d68b3672b9..5b3c92f4bd7 100644
>> --- a/libstdc++-v3/configure.ac
>> +++ b/libstdc++-v3/configure.ac
>> @@ -468,6 +468,10 @@ GLIBCXX_CHECK_X86_RDRAND
>>  # Check if assembler supports rdseed opcode.
>>  GLIBCXX_CHECK_X86_RDSEED
>>
>> +# Check for other random number APIs
>> +GLIBCXX_CHECK_GETENTROPY
>> +GLIBCXX_CHECK_ARC4RANDOM
>> +
>>  # This depends on GLIBCXX_ENABLE_SYMVERS and GLIBCXX_IS_NATIVE.
>>  GLIBCXX_CONFIGURE_TESTSUITE
>>
>> diff --git a/libstdc++-v3/src/c++11/random.cc
>> b/libstdc++-v3/src/c++11/random.cc
>> index 4b88818646f..4a553e0d84f 100644
>> --- a/libstdc++-v3/src/c++11/random.cc
>> +++ b/libstdc++-v3/src/c++11/random.cc
>> @@ -68,7 +68,12 @@
>>  # include <stdlib.h>
>>  #endif
>>
>> -#if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM
>> +#ifdef _GLIBCXX_HAVE_GETENTROPY
>> +# include <unistd.h>
>> +#endif
>> +
>> +#if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM \
>> +  || _GLIBCXX_HAVE_GETENTROPY
>>  // The OS provides a source of randomness we can use.
>>  # pragma GCC poison _M_mt
>>  #elif defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
>> @@ -166,6 +171,25 @@ namespace std _GLIBCXX_VISIBILITY(default)
>>      }
>>  #endif
>>
>> +#ifdef _GLIBCXX_HAVE_GETENTROPY
>> +    unsigned int
>> +    __libc_getentropy(void*)
>> +    {
>> +      unsigned int val;
>> +      if (::getentropy(&val, sizeof(val)) != 0)
>> +       std::__throw_runtime_error(__N("random_device: getentropy
>> failed"));
>> +      return val;
>> +    }
>> +#endif
>> +
>> +#ifdef _GLIBCXX_HAVE_ARC4RANDOM
>> +    unsigned int
>> +    __libc_arc4random(void*)
>> +    {
>> +      return ::arc4random();
>> +    }
>> +#endif
>> +
>>  #ifdef USE_LCG
>>      // TODO: use this to seed std::mt19937 engine too.
>>      unsigned
>> @@ -214,7 +238,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
>>  #endif
>>
>>      enum Which : unsigned {
>> -      device_file = 1, prng = 2, rand_s = 4,
>> +      device_file = 1, prng = 2, rand_s = 4, getentropy = 8, arc4random
>> = 16,
>>        rdseed = 64, rdrand = 128, darn = 256,
>>        any = 0xffff
>>      };
>> @@ -256,6 +280,16 @@ namespace std _GLIBCXX_VISIBILITY(default)
>>         return device_file;
>>  #endif
>>
>> +#ifdef _GLIBCXX_HAVE_ARC4RANDOM
>> +      if (func == __libc_arc4random)
>> +       return arc4random;
>> +#endif
>> +
>> +#ifdef _GLIBCXX_HAVE_GETENTROPY
>> +      if (func == __libc_getentropy)
>> +       return getentropy;
>> +#endif
>> +
>>  #ifdef USE_LCG
>>        if (func == &__lcg)
>>         return prng;
>> @@ -311,6 +345,14 @@ namespace std _GLIBCXX_VISIBILITY(default)
>>      else if (token == "rand_s")
>>        which = rand_s;
>>  #endif // _GLIBCXX_USE_CRT_RAND_S
>> +#ifdef _GLIBCXX_HAVE_GETENTROPY
>> +    else if (token == "getentropy")
>> +      which = getentropy;
>> +#endif // _GLIBCXX_HAVE_GETENTROPY
>> +#ifdef _GLIBCXX_HAVE_ARC4RANDOM
>> +    else if (token == "arc4random")
>> +      which = arc4random;
>> +#endif // _GLIBCXX_HAVE_ARC4RANDOM
>>  #ifdef _GLIBCXX_USE_DEV_RANDOM
>>      else if (token == "/dev/urandom" || token == "/dev/random")
>>        {
>> @@ -395,6 +437,26 @@ namespace std _GLIBCXX_VISIBILITY(default)
>>        }
>>  #endif // USE_DARN
>>
>> +#ifdef _GLIBCXX_HAVE_ARC4RANDOM
>> +    if (which & arc4random)
>> +      {
>> +       _M_func = &__libc_arc4random;
>> +       return;
>> +      }
>> +#endif // _GLIBCXX_HAVE_ARC4RANDOM
>> +
>> +#ifdef _GLIBCXX_HAVE_GETENTROPY
>> +    if (which & getentropy)
>> +      {
>> +       unsigned int i;
>> +       if (::getentropy(&i, sizeof(i)) == 0) // On linux the syscall can
>> fail.
>> +         {
>> +           _M_func = &__libc_getentropy;
>> +           return;
>> +         }
>> +      }
>> +#endif // _GLIBCXX_HAVE_GETENTROPY
>> +
>>  #ifdef _GLIBCXX_USE_DEV_RANDOM
>>      if (which & device_file)
>>      {
>> @@ -548,6 +610,9 @@ namespace std _GLIBCXX_VISIBILITY(default)
>>      case rdseed:
>>      case darn:
>>        return (double) max;
>> +    case arc4random:
>> +    case getentropy:
>> +      return (double) max;
>>      case rand_s:
>>      case prng:
>>        return 0.0;
>> diff --git
>> a/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
>> b/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
>> index d6ac3a37c64..e13484e03a5 100644
>> ---
>> a/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
>> +++
>> b/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
>> @@ -53,6 +53,7 @@ test03()
>>    const std::string tokens[] = {
>>      "rdseed", "rdrand", "darn",
>>      "rand_s", "/dev/urandom", "/dev/random",
>> +    "getentropy", "arc4random",
>>      "mt19937", "prng"
>>    };
>>    int count = 0;
>> diff --git
>> a/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
>> b/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
>> index 6f3ebb1b38e..63b7043bf9b 100644
>> --- a/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
>> +++ b/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
>> @@ -28,6 +28,13 @@ test01()
>>        const double entropy = std::random_device(token).entropy();
>>        VERIFY( entropy == max );
>>      }
>> +
>> +    for (auto token : { "getentropy", "arc4random" })
>> +    if (__gnu_test::random_device_available(token))
>> +    {
>> +      const double entropy = std::random_device(token).entropy();
>> +      VERIFY( entropy == max );
>> +    }
>>  }
>>
>>  int
>> --
>> 2.31.1
>>
>>
diff mbox series

Patch

diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 90ecc4a87a2..497af5723e1 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -4830,6 +4830,52 @@  AC_DEFUN([GLIBCXX_CHECK_EXCEPTION_PTR_SYMVER], [
   fi
 ])
 
+dnl
+dnl Check whether getentropy is present in <unistd.h>.
+dnl
+AC_DEFUN([GLIBCXX_CHECK_GETENTROPY], [
+
+  AC_LANG_SAVE
+  AC_LANG_CPLUSPLUS
+  AC_MSG_CHECKING([for getentropy])
+  AC_CACHE_VAL(glibcxx_cv_getentropy, [
+      AC_TRY_COMPILE(
+	[#include <unistd.h>],
+	[unsigned i;
+	 ::getentropy(&i, sizeof(i));],
+	[glibcxx_cv_getentropy=yes], [glibcxx_cv_getentropy=no])
+    ])
+
+  if test $glibcxx_cv_getentropy = yes; then
+    AC_DEFINE(HAVE_GETENTROPY, 1, [Define if getentropy is available in <unistd.h>.])
+  fi
+  AC_MSG_RESULT($glibcxx_cv_getentropy)
+  AC_LANG_RESTORE
+])
+
+dnl
+dnl Check whether arc4random is present in <stdlib.h>.
+dnl
+AC_DEFUN([GLIBCXX_CHECK_ARC4RANDOM], [
+
+  AC_LANG_SAVE
+  AC_LANG_CPLUSPLUS
+  AC_MSG_CHECKING([for arc4random])
+  AC_CACHE_VAL(glibcxx_cv_arc4random, [
+      AC_TRY_COMPILE(
+	[#include <stdlib.h>],
+	[unsigned i = ::arc4random();],
+	[glibcxx_cv_arc4random=yes], [glibcxx_cv_arc4random=no])
+    ])
+
+  if test $glibcxx_cv_arc4random = yes; then
+    AC_DEFINE(HAVE_ARC4RANDOM, 1, [Define if arc4random is available in <stdlib.h>.])
+  fi
+  AC_MSG_RESULT($glibcxx_cv_arc4random)
+  AC_LANG_RESTORE
+])
+
+
 # Macros from the top-level gcc directory.
 m4_include([../config/gc++filt.m4])
 m4_include([../config/tls.m4])
diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in
index 228a758325e..420021fcb1a 100644
--- a/libstdc++-v3/config.h.in
+++ b/libstdc++-v3/config.h.in
@@ -9,6 +9,9 @@ 
 /* Define to 1 if you have the `aligned_alloc' function. */
 #undef HAVE_ALIGNED_ALLOC
 
+/* Define if arc4random is available in <stdlib.h>. */
+#undef HAVE_ARC4RANDOM
+
 /* Define to 1 if you have the <arpa/inet.h> header file. */
 #undef HAVE_ARPA_INET_H
 
@@ -132,6 +135,9 @@ 
 /* Define to 1 if you have the `frexpl' function. */
 #undef HAVE_FREXPL
 
+/* Define if getentropy is available in <unistd.h>. */
+#undef HAVE_GETENTROPY
+
 /* Define if _Unwind_GetIPInfo is available. */
 #undef HAVE_GETIPINFO
 
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index c1aea827070..21371031b66 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -75429,6 +75429,109 @@  $as_echo "#define _GLIBCXX_X86_RDSEED 1" >>confdefs.h
 $as_echo "$ac_cv_x86_rdseed" >&6; }
 
 
+# Check for other random number APIs
+
+
+
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getentropy" >&5
+$as_echo_n "checking for getentropy... " >&6; }
+  if ${glibcxx_cv_getentropy+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unistd.h>
+int
+main ()
+{
+unsigned i;
+	 ::getentropy(&i, sizeof(i));
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  glibcxx_cv_getentropy=yes
+else
+  glibcxx_cv_getentropy=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+
+  if test $glibcxx_cv_getentropy = yes; then
+
+$as_echo "#define HAVE_GETENTROPY 1" >>confdefs.h
+
+  fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_getentropy" >&5
+$as_echo "$glibcxx_cv_getentropy" >&6; }
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for arc4random" >&5
+$as_echo_n "checking for arc4random... " >&6; }
+  if ${glibcxx_cv_arc4random+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+int
+main ()
+{
+unsigned i = ::arc4random();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  glibcxx_cv_arc4random=yes
+else
+  glibcxx_cv_arc4random=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+
+  if test $glibcxx_cv_arc4random = yes; then
+
+$as_echo "#define HAVE_ARC4RANDOM 1" >>confdefs.h
+
+  fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_arc4random" >&5
+$as_echo "$glibcxx_cv_arc4random" >&6; }
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
 # This depends on GLIBCXX_ENABLE_SYMVERS and GLIBCXX_IS_NATIVE.
 
   # Do checks for resource limit functions.
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index 2d68b3672b9..5b3c92f4bd7 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -468,6 +468,10 @@  GLIBCXX_CHECK_X86_RDRAND
 # Check if assembler supports rdseed opcode.
 GLIBCXX_CHECK_X86_RDSEED
 
+# Check for other random number APIs
+GLIBCXX_CHECK_GETENTROPY
+GLIBCXX_CHECK_ARC4RANDOM
+
 # This depends on GLIBCXX_ENABLE_SYMVERS and GLIBCXX_IS_NATIVE.
 GLIBCXX_CONFIGURE_TESTSUITE
 
diff --git a/libstdc++-v3/src/c++11/random.cc b/libstdc++-v3/src/c++11/random.cc
index 4b88818646f..4a553e0d84f 100644
--- a/libstdc++-v3/src/c++11/random.cc
+++ b/libstdc++-v3/src/c++11/random.cc
@@ -68,7 +68,12 @@ 
 # include <stdlib.h>
 #endif
 
-#if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM
+#ifdef _GLIBCXX_HAVE_GETENTROPY
+# include <unistd.h>
+#endif
+
+#if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM \
+  || _GLIBCXX_HAVE_GETENTROPY
 // The OS provides a source of randomness we can use.
 # pragma GCC poison _M_mt
 #elif defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
@@ -166,6 +171,25 @@  namespace std _GLIBCXX_VISIBILITY(default)
     }
 #endif
 
+#ifdef _GLIBCXX_HAVE_GETENTROPY
+    unsigned int
+    __libc_getentropy(void*)
+    {
+      unsigned int val;
+      if (::getentropy(&val, sizeof(val)) != 0)
+	std::__throw_runtime_error(__N("random_device: getentropy failed"));
+      return val;
+    }
+#endif
+
+#ifdef _GLIBCXX_HAVE_ARC4RANDOM
+    unsigned int
+    __libc_arc4random(void*)
+    {
+      return ::arc4random();
+    }
+#endif
+
 #ifdef USE_LCG
     // TODO: use this to seed std::mt19937 engine too.
     unsigned
@@ -214,7 +238,7 @@  namespace std _GLIBCXX_VISIBILITY(default)
 #endif
 
     enum Which : unsigned {
-      device_file = 1, prng = 2, rand_s = 4,
+      device_file = 1, prng = 2, rand_s = 4, getentropy = 8, arc4random = 16,
       rdseed = 64, rdrand = 128, darn = 256,
       any = 0xffff
     };
@@ -256,6 +280,16 @@  namespace std _GLIBCXX_VISIBILITY(default)
 	return device_file;
 #endif
 
+#ifdef _GLIBCXX_HAVE_ARC4RANDOM
+      if (func == __libc_arc4random)
+	return arc4random;
+#endif
+
+#ifdef _GLIBCXX_HAVE_GETENTROPY
+      if (func == __libc_getentropy)
+	return getentropy;
+#endif
+
 #ifdef USE_LCG
       if (func == &__lcg)
 	return prng;
@@ -311,6 +345,14 @@  namespace std _GLIBCXX_VISIBILITY(default)
     else if (token == "rand_s")
       which = rand_s;
 #endif // _GLIBCXX_USE_CRT_RAND_S
+#ifdef _GLIBCXX_HAVE_GETENTROPY
+    else if (token == "getentropy")
+      which = getentropy;
+#endif // _GLIBCXX_HAVE_GETENTROPY
+#ifdef _GLIBCXX_HAVE_ARC4RANDOM
+    else if (token == "arc4random")
+      which = arc4random;
+#endif // _GLIBCXX_HAVE_ARC4RANDOM
 #ifdef _GLIBCXX_USE_DEV_RANDOM
     else if (token == "/dev/urandom" || token == "/dev/random")
       {
@@ -395,6 +437,26 @@  namespace std _GLIBCXX_VISIBILITY(default)
       }
 #endif // USE_DARN
 
+#ifdef _GLIBCXX_HAVE_ARC4RANDOM
+    if (which & arc4random)
+      {
+	_M_func = &__libc_arc4random;
+	return;
+      }
+#endif // _GLIBCXX_HAVE_ARC4RANDOM
+
+#ifdef _GLIBCXX_HAVE_GETENTROPY
+    if (which & getentropy)
+      {
+	unsigned int i;
+	if (::getentropy(&i, sizeof(i)) == 0) // On linux the syscall can fail.
+	  {
+	    _M_func = &__libc_getentropy;
+	    return;
+	  }
+      }
+#endif // _GLIBCXX_HAVE_GETENTROPY
+
 #ifdef _GLIBCXX_USE_DEV_RANDOM
     if (which & device_file)
     {
@@ -548,6 +610,9 @@  namespace std _GLIBCXX_VISIBILITY(default)
     case rdseed:
     case darn:
       return (double) max;
+    case arc4random:
+    case getentropy:
+      return (double) max;
     case rand_s:
     case prng:
       return 0.0;
diff --git a/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc b/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
index d6ac3a37c64..e13484e03a5 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/random_device/cons/token.cc
@@ -53,6 +53,7 @@  test03()
   const std::string tokens[] = {
     "rdseed", "rdrand", "darn",
     "rand_s", "/dev/urandom", "/dev/random",
+    "getentropy", "arc4random",
     "mt19937", "prng"
   };
   int count = 0;
diff --git a/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc b/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
index 6f3ebb1b38e..63b7043bf9b 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/random_device/entropy.cc
@@ -28,6 +28,13 @@  test01()
       const double entropy = std::random_device(token).entropy();
       VERIFY( entropy == max );
     }
+
+    for (auto token : { "getentropy", "arc4random" })
+    if (__gnu_test::random_device_available(token))
+    {
+      const double entropy = std::random_device(token).entropy();
+      VERIFY( entropy == max );
+    }
 }
 
 int