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

Jonathan Wakely jwakely@redhat.com
Tue Nov 9 14:41:59 GMT 2021


Tested x86_64-linux, and Iain Sandoe tested the arc4random code on
darwin too. Pushed to trunk.


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.

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/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 07713e5c67f..e56afbc9c97 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



More information about the Gcc-patches mailing list