[libcxx-commits] [libcxx] d202c76 - [libc++] Start using `arc4random()` to implement `std::random_device` on Apple

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jan 12 08:24:28 PST 2022


Author: Louis Dionne
Date: 2022-01-12T11:24:23-05:00
New Revision: d202c76441e114f933057492f4bf15aa0d444867

URL: https://github.com/llvm/llvm-project/commit/d202c76441e114f933057492f4bf15aa0d444867
DIFF: https://github.com/llvm/llvm-project/commit/d202c76441e114f933057492f4bf15aa0d444867.diff

LOG: [libc++] Start using `arc4random()` to implement `std::random_device` on Apple

On Apple platforms, arc4random is faster than /dev/urandom, and it is
the recommended user-space RNG according to Apple's own OS folks.

This commit adds an ABI switch to guard ABI-break-protections in
std::random_device, and starts using arc4random instead of /dev/urandom
to implement std::random_device on Apple platforms.

Note that previously, `std::random_device` would allow passing a custom
token to its constructor, and that token would be interpreted as the name
of a file to read entropy from. This was implementation-defined and
undocumented. After this change, Apple platforms will be using arc4random()
instead, and any custom token passed to the constructor will be ignored.
This behavioral change will also impact other platforms that use the
arc4random() implementation, such as OpenBSD. This should be fine since
that is effectively a relaxation of the constructor's requirements.

rdar://86638350

Differential Revision: https://reviews.llvm.org/D116045

Added: 
    

Modified: 
    libcxx/docs/ReleaseNotes.rst
    libcxx/include/__config
    libcxx/include/__random/random_device.h
    libcxx/src/random.cpp
    libcxx/test/std/numerics/rand/rand.device/ctor.pass.cpp
    libcxx/test/std/numerics/rand/rand.device/eval.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index 5f45c3c5e7743..1a8c0071cec23 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -114,6 +114,11 @@ ABI Changes
   comment `here <https://reviews.llvm.org/D109459>`_ if you are broken by this change
   and need to define the macro.
 
+- On Apple platforms, ``std::random_device`` is now implemented on top of ``arc4random()``
+  instead of reading from ``/dev/urandom``. Any implementation-defined token used when
+  constructing a ``std::random_device`` will now be ignored instead of interpreted as a
+  file to read entropy from.
+
 Build System Changes
 --------------------
 

diff  --git a/libcxx/include/__config b/libcxx/include/__config
index 98f011e7c6ada..654816b78f295 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -107,6 +107,13 @@
 #  define _LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI
 // Enable clang::trivial_abi on std::shared_ptr and std::weak_ptr
 #  define _LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI
+// std::random_device holds some state when it uses an implementation that gets
+// entropy from a file (see _LIBCPP_USING_DEV_RANDOM). When switching from this
+// implementation to another one on a platform that has already shipped
+// std::random_device, one needs to retain the same object layout to remain ABI
+// compatible. This switch removes these workarounds for platforms that don't care
+// about ABI compatibility.
+#  define _LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT
 #elif _LIBCPP_ABI_VERSION == 1
 #  if !defined(_LIBCPP_OBJECT_FORMAT_COFF)
 // Enable compiling copies of now inline methods into the dylib to support
@@ -371,7 +378,7 @@
 //      Use rand_s(), for use on Windows.
 //      When this option is used, the token passed to `std::random_device`'s
 //      constructor *must* be "/dev/urandom" -- anything else is an error.
-#if defined(__OpenBSD__)
+#if defined(__OpenBSD__) || defined(__APPLE__)
 #  define _LIBCPP_USING_ARC4_RANDOM
 #elif defined(__wasi__)
 #  define _LIBCPP_USING_GETENTROPY

diff  --git a/libcxx/include/__random/random_device.h b/libcxx/include/__random/random_device.h
index 835f726fdbccc..ef11977f9b779 100644
--- a/libcxx/include/__random/random_device.h
+++ b/libcxx/include/__random/random_device.h
@@ -27,7 +27,26 @@ class _LIBCPP_TYPE_VIS random_device
 {
 #ifdef _LIBCPP_USING_DEV_RANDOM
     int __f_;
+#elif !defined(_LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT)
+#   if defined(__clang__)
+#       pragma clang diagnostic push
+#       pragma clang diagnostic ignored "-Wunused-private-field"
+#   endif
+
+    // Apple platforms used to use the `_LIBCPP_USING_DEV_RANDOM` code path, and now
+    // use `arc4random()` as of this comment. In order to avoid breaking the ABI, we
+    // retain the same layout as before.
+#   if defined(__APPLE__)
+    int __padding_; // padding to fake the `__f_` field above
+#   endif
+
+    // ... vendors can add workarounds here if they switch to a 
diff erent representation ...
+
+#   if defined(__clang__)
+#       pragma clang diagnostic pop
+#   endif
 #endif
+
 public:
     // types
     typedef unsigned result_type;

diff  --git a/libcxx/src/random.cpp b/libcxx/src/random.cpp
index 5590db85e48ad..6472a8dbcba3e 100644
--- a/libcxx/src/random.cpp
+++ b/libcxx/src/random.cpp
@@ -68,10 +68,8 @@ random_device::operator()()
 
 #elif defined(_LIBCPP_USING_ARC4_RANDOM)
 
-random_device::random_device(const string& __token)
+random_device::random_device(const string&)
 {
-    if (__token != "/dev/urandom")
-        __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
 }
 
 random_device::~random_device()

diff  --git a/libcxx/test/std/numerics/rand/rand.device/ctor.pass.cpp b/libcxx/test/std/numerics/rand/rand.device/ctor.pass.cpp
index 6abd57827c336..5e00cb0bc8126 100644
--- a/libcxx/test/std/numerics/rand/rand.device/ctor.pass.cpp
+++ b/libcxx/test/std/numerics/rand/rand.device/ctor.pass.cpp
@@ -9,6 +9,11 @@
 // See https://llvm.org/PR20183
 // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11}}
 
+// The behavior of std::random_device changed on Apple platforms with
+// https://llvm.org/D116045.
+// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
+// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{11|12}}
+
 // UNSUPPORTED: libcpp-has-no-random-device
 
 // <random>
@@ -59,13 +64,24 @@ int main(int, char**) {
   }
   // Check the validity of various tokens
   {
-    check_random_device_invalid("wrong file");
-    check_random_device_invalid("/dev/whatever");
+#if defined(_LIBCPP_USING_ARC4_RANDOM)
+    check_random_device_valid("/dev/urandom");
+    check_random_device_valid("/dev/random");
+    check_random_device_valid("/dev/null");
+    check_random_device_valid("/dev/nonexistent");
+    check_random_device_valid("wrong file");
+#elif defined(_LIBCPP_USING_DEV_RANDOM)
     check_random_device_valid("/dev/urandom");
-#if defined(_LIBCPP_USING_DEV_RANDOM)
     check_random_device_valid("/dev/random");
+    check_random_device_valid("/dev/null");
+    check_random_device_invalid("/dev/nonexistent");
+    check_random_device_invalid("wrong file");
 #else
+    check_random_device_valid("/dev/urandom");
     check_random_device_invalid("/dev/random");
+    check_random_device_invalid("/dev/null");
+    check_random_device_invalid("/dev/nonexistent");
+    check_random_device_invalid("wrong file");
 #endif
   }
 

diff  --git a/libcxx/test/std/numerics/rand/rand.device/eval.pass.cpp b/libcxx/test/std/numerics/rand/rand.device/eval.pass.cpp
index 8d0b507d94613..3705ac14532f7 100644
--- a/libcxx/test/std/numerics/rand/rand.device/eval.pass.cpp
+++ b/libcxx/test/std/numerics/rand/rand.device/eval.pass.cpp
@@ -6,9 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-// See https://llvm.org/PR20183
-// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11}}
-
 // UNSUPPORTED: libcpp-has-no-random-device
 
 // <random>


        


More information about the libcxx-commits mailing list