[libcxx-commits] [libcxx] e0d0129 - [libc++] Allow building libc++ on platforms without a random device

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Oct 15 09:20:58 PDT 2020


Author: Louis Dionne
Date: 2020-10-15T12:20:29-04:00
New Revision: e0d01294bc124211a8ffb55e69162eb34a242680

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

LOG: [libc++] Allow building libc++ on platforms without a random device

Some platforms, like several embedded platforms, do not provide a source
of randomness through a random device. This commit makes it possible to
build and test libc++ for such platforms, i.e. without std::random_device.

Surprisingly, the only functionality that doesn't work on such platforms
is std::random_device itself -- everything else in <random> still works,
one just has to find alternative ways to seed the PRNGs.

Added: 
    libcxx/cmake/caches/Generic-no-random_device.cmake
    libcxx/test/libcxx/numerics/rand/rand.device/has-no-random-device.verify.cpp

Modified: 
    libcxx/CMakeLists.txt
    libcxx/include/__config_site.in
    libcxx/include/random
    libcxx/src/CMakeLists.txt
    libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.copy_file/copy_file_large.pass.cpp
    libcxx/test/std/numerics/rand/rand.device/ctor.pass.cpp
    libcxx/test/std/numerics/rand/rand.device/entropy.pass.cpp
    libcxx/test/std/numerics/rand/rand.device/eval.pass.cpp
    libcxx/test/support/filesystem_test_helper.h
    libcxx/utils/ci/buildkite-pipeline.yml
    libcxx/utils/ci/run-buildbot.sh
    libcxx/utils/libcxx/test/features.py

Removed: 
    


################################################################################
diff  --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index f67f417de238..69ff183770ad 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -109,6 +109,12 @@ option(LIBCXX_ENABLE_DEBUG_MODE_SUPPORT
    By default, this is turned on. If you turn it off and try to enable the
    debug mode when compiling a program against libc++, it will fail to link
    since the required support isn't provided in the library." ON)
+option(LIBCXX_ENABLE_RANDOM_DEVICE
+  "Whether to include support for std::random_device in the library. Disabling
+   this can be useful when building the library for platforms that don't have
+   a source of randomness, such as some embedded platforms. When this is not
+   supported, most of <random> will still be available, but std::random_device
+   will not." ON)
 option(LIBCXX_TEST_GDB_PRETTY_PRINTERS "Test gdb pretty printers." OFF)
 set(LIBCXX_TEST_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/test/configs/legacy.cfg.in" CACHE STRING
     "The Lit testing configuration to use when running the tests.")
@@ -836,6 +842,7 @@ config_define_if(LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY _LIBCPP_HAS_THREAD_LIBRARY
 config_define_if(LIBCXX_HAS_MUSL_LIBC _LIBCPP_HAS_MUSL_LIBC)
 config_define_if(LIBCXX_NO_VCRUNTIME _LIBCPP_NO_VCRUNTIME)
 config_define_if(LIBCXX_ENABLE_PARALLEL_ALGORITHMS _LIBCPP_HAS_PARALLEL_ALGORITHMS)
+config_define_if_not(LIBCXX_ENABLE_RANDOM_DEVICE _LIBCPP_HAS_NO_RANDOM_DEVICE)
 
 if (LIBCXX_ABI_DEFINES)
   set(abi_defines)

diff  --git a/libcxx/cmake/caches/Generic-no-random_device.cmake b/libcxx/cmake/caches/Generic-no-random_device.cmake
new file mode 100644
index 000000000000..e9b4cc60cc80
--- /dev/null
+++ b/libcxx/cmake/caches/Generic-no-random_device.cmake
@@ -0,0 +1 @@
+set(LIBCXX_ENABLE_RANDOM_DEVICE OFF CACHE BOOL "")

diff  --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in
index a6984b2eefc1..908fb1e674ce 100644
--- a/libcxx/include/__config_site.in
+++ b/libcxx/include/__config_site.in
@@ -32,6 +32,7 @@
 #endif
 #cmakedefine _LIBCPP_ABI_NAMESPACE @_LIBCPP_ABI_NAMESPACE@
 #cmakedefine _LIBCPP_HAS_PARALLEL_ALGORITHMS
+#cmakedefine _LIBCPP_HAS_NO_RANDOM_DEVICE
 
 @_LIBCPP_ABI_DEFINES@
 

diff  --git a/libcxx/include/random b/libcxx/include/random
index ce3d135e064a..4321195c4f0e 100644
--- a/libcxx/include/random
+++ b/libcxx/include/random
@@ -3477,6 +3477,8 @@ typedef shuffle_order_engine<minstd_rand0, 256>                         knuth_b;
 
 // random_device
 
+#if !defined(_LIBCPP_HAS_NO_RANDOM_DEVICE)
+
 class _LIBCPP_TYPE_VIS random_device
 {
 #ifdef _LIBCPP_USING_DEV_RANDOM
@@ -3511,6 +3513,8 @@ private:
     random_device& operator=(const random_device&); // = delete;
 };
 
+#endif // !_LIBCPP_HAS_NO_RANDOM_DEVICE
+
 // seed_seq
 
 class _LIBCPP_TEMPLATE_VIS seed_seq

diff  --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index eab2152b5126..3c5bc1ebc576 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -27,7 +27,6 @@ set(LIBCXX_SOURCES
   mutex_destructor.cpp
   new.cpp
   optional.cpp
-  random.cpp
   random_shuffle.cpp
   regex.cpp
   shared_mutex.cpp
@@ -61,6 +60,12 @@ if (LIBCXX_ENABLE_DEBUG_MODE_SUPPORT)
     )
 endif()
 
+if (LIBCXX_ENABLE_RANDOM_DEVICE)
+  list(APPEND LIBCXX_SOURCES
+    random.cpp
+    )
+endif()
+
 if(WIN32)
   list(APPEND LIBCXX_SOURCES
     support/win32/locale_win32.cpp

diff  --git a/libcxx/test/libcxx/numerics/rand/rand.device/has-no-random-device.verify.cpp b/libcxx/test/libcxx/numerics/rand/rand.device/has-no-random-device.verify.cpp
new file mode 100644
index 000000000000..66a3afb25645
--- /dev/null
+++ b/libcxx/test/libcxx/numerics/rand/rand.device/has-no-random-device.verify.cpp
@@ -0,0 +1,19 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that std::random_device is not available in namespace std:: when
+// libc++ is built without support for random device.
+
+// REQUIRES: libcpp-has-no-random-device
+
+#include <random>
+
+int main(int, char**) {
+  std::random_device d; // expected-error {{no type named 'random_device' in namespace 'std'}}
+  return 0;
+}

diff  --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.copy_file/copy_file_large.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.copy_file/copy_file_large.pass.cpp
index d7bdbdb2de17..1f435840a24a 100644
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.copy_file/copy_file_large.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.copy_file/copy_file_large.pass.cpp
@@ -19,7 +19,6 @@
 
 #include "filesystem_include.h"
 #include <cassert>
-#include <chrono>
 #include <fstream>
 #include <string>
 
@@ -31,14 +30,6 @@ using namespace fs;
 
 TEST_SUITE(filesystem_copy_file_test_suite)
 
-static std::string random_hex_chars(uintmax_t size) {
-  std::string data;
-  data.reserve(size);
-  for (uintmax_t I = 0; I < size; ++I)
-    data.push_back(random_utils::random_hex_char());
-  return data;
-}
-
 // This test is intended to test 'sendfile's 2gb limit for a single call, and
 // to ensure that libc++ correctly copies files larger than that limit.
 // However it requires allocating ~5GB of filesystem space. This might not
@@ -58,12 +49,10 @@ TEST_CASE(large_file) {
     TEST_UNSUPPORTED();
   }
 
-  // Use python to create a file right at the size limit.
+  // Create a file right at the size limit. The file is full of '\0's.
   const path file = env.create_file("source", sendfile_size_limit);
-  // Create some random data that looks 
diff erent than the data before the
-  // size limit.
-  const std::string additional_data = random_hex_chars(additional_size);
-  // Append this known data to the end of the source file.
+  const std::string additional_data(additional_size, 'x');
+  // Append known data to the end of the source file.
   {
     std::ofstream outf(file.native(), std::ios_base::app);
     TEST_REQUIRE(outf.good());

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 b0d8605387d8..b12a7bb7598b 100644
--- a/libcxx/test/std/numerics/rand/rand.device/ctor.pass.cpp
+++ b/libcxx/test/std/numerics/rand/rand.device/ctor.pass.cpp
@@ -12,6 +12,8 @@
 // XFAIL: with_system_cxx_lib=macosx10.10
 // XFAIL: with_system_cxx_lib=macosx10.9
 
+// UNSUPPORTED: libcpp-has-no-random-device
+
 // <random>
 
 // class random_device;

diff  --git a/libcxx/test/std/numerics/rand/rand.device/entropy.pass.cpp b/libcxx/test/std/numerics/rand/rand.device/entropy.pass.cpp
index e93657c48722..4f09d05012ea 100644
--- a/libcxx/test/std/numerics/rand/rand.device/entropy.pass.cpp
+++ b/libcxx/test/std/numerics/rand/rand.device/entropy.pass.cpp
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+// UNSUPPORTED: libcpp-has-no-random-device
+
 // <random>
 
 // class random_device;

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 d68c67a0a678..38522d8d87c1 100644
--- a/libcxx/test/std/numerics/rand/rand.device/eval.pass.cpp
+++ b/libcxx/test/std/numerics/rand/rand.device/eval.pass.cpp
@@ -12,6 +12,8 @@
 // XFAIL: with_system_cxx_lib=macosx10.10
 // XFAIL: with_system_cxx_lib=macosx10.9
 
+// UNSUPPORTED: libcpp-has-no-random-device
+
 // <random>
 
 // class random_device;

diff  --git a/libcxx/test/support/filesystem_test_helper.h b/libcxx/test/support/filesystem_test_helper.h
index 2a626f79daa4..448f9851293e 100644
--- a/libcxx/test/support/filesystem_test_helper.h
+++ b/libcxx/test/support/filesystem_test_helper.h
@@ -3,13 +3,12 @@
 
 #include "filesystem_include.h"
 
-#include <sys/stat.h> // for mkdir, mkfifo
+#include <sys/stat.h> // for stat, mkdir, mkfifo
 #include <unistd.h> // for ftruncate, link, symlink, getcwd, chdir
 
 #include <cassert>
 #include <cstdio> // for printf
 #include <string>
-#include <random>
 #include <chrono>
 #include <vector>
 #include <regex>
@@ -24,23 +23,25 @@
 # include <sys/un.h>
 #endif
 
-namespace random_utils {
-inline char to_hex(int ch) {
-  return ch < 10 ? static_cast<char>('0' + ch)
-                 : static_cast<char>('a' + (ch - 10));
-}
-
-inline char random_hex_char() {
-  static std::mt19937 rd{std::random_device{}()};
-  static std::uniform_int_distribution<int> mrand{0, 15};
-  return to_hex(mrand(rd));
-}
+namespace utils {
+    inline std::string getcwd() {
+        // Assume that path lengths are not greater than this.
+        // This should be fine for testing purposes.
+        char buf[4096];
+        char* ret = ::getcwd(buf, sizeof(buf));
+        assert(ret && "getcwd failed");
+        return std::string(ret);
+    }
 
-} // namespace random_utils
+    inline bool exists(std::string const& path) {
+        struct ::stat tmp;
+        return ::stat(path.c_str(), &tmp) == 0;
+    }
+} // end namespace utils
 
 struct scoped_test_env
 {
-    scoped_test_env() : test_root(random_path()) {
+    scoped_test_env() : test_root(available_cwd_path()) {
         std::string cmd = "mkdir -p " + test_root.native();
         int ret = std::system(cmd.c_str());
         assert(ret == 0);
@@ -174,20 +175,20 @@ struct scoped_test_env
     fs::path test_root;
 
 private:
-    static std::string unique_path_suffix() {
-        std::string model = "test.%%%%%%";
-        for (auto & ch :  model) {
-          if (ch == '%')
-            ch = random_utils::random_hex_char();
+    // This could potentially introduce a filesystem race if multiple
+    // scoped_test_envs were created concurrently in the same test (hence
+    // sharing the same cwd). However, it is fairly unlikely to happen as
+    // we generally don't use scoped_test_env from multiple threads, so
+    // this is deemed acceptable.
+    static inline fs::path available_cwd_path() {
+        fs::path const cwd = utils::getcwd();
+        fs::path const tmp = fs::temp_directory_path();
+        fs::path const base = tmp / cwd.filename();
+        int i = 0;
+        fs::path p = base / ("static_env." + std::to_string(i));
+        while (utils::exists(p)) {
+            p = fs::path(base) / ("static_env." + std::to_string(++i));
         }
-        return model;
-    }
-
-    // This could potentially introduce a filesystem race with other tests
-    // running at the same time, but oh well, it's just test code.
-    static inline fs::path random_path() {
-        fs::path tmp = fs::temp_directory_path();
-        fs::path p = fs::path(tmp) / unique_path_suffix();
         return p;
     }
 };
@@ -301,15 +302,10 @@ class static_test_env {
 };
 
 struct CWDGuard {
-  // Assume that path lengths are not greater than this.
-  // This should be fine for testing purposes.
-  char OldCWD[4096];
-  CWDGuard() {
-    char* ret = ::getcwd(OldCWD, sizeof(OldCWD));
-    assert(ret && "getcwd failed");
-  }
+  std::string oldCwd_;
+  CWDGuard() : oldCwd_(utils::getcwd()) { }
   ~CWDGuard() {
-    int ret = ::chdir(OldCWD);
+    int ret = ::chdir(oldCwd_.c_str());
     assert(ret == 0 && "chdir failed");
   }
 

diff  --git a/libcxx/utils/ci/buildkite-pipeline.yml b/libcxx/utils/ci/buildkite-pipeline.yml
index 929ee98be464..6d416a36cba2 100644
--- a/libcxx/utils/ci/buildkite-pipeline.yml
+++ b/libcxx/utils/ci/buildkite-pipeline.yml
@@ -80,6 +80,11 @@ steps:
     agents:
       queue: "libcxx-builders"
 
+  - label: "No random device"
+    command: "set -o pipefail && libcxx/utils/ci/run-buildbot.sh generic-no-random_device | libcxx/utils/ci/phabricator-report"
+    agents:
+      queue: "libcxx-builders"
+
   - label: "MacOS C++20"
     command: "set -o pipefail && libcxx/utils/ci/run-buildbot.sh generic-cxx2a | libcxx/utils/ci/phabricator-report"
     agents:

diff  --git a/libcxx/utils/ci/run-buildbot.sh b/libcxx/utils/ci/run-buildbot.sh
index 279291d50888..87a1f0f1d622 100755
--- a/libcxx/utils/ci/run-buildbot.sh
+++ b/libcxx/utils/ci/run-buildbot.sh
@@ -109,6 +109,12 @@ generic-nodebug)
     args+=("-DLLVM_LIT_ARGS=-sv --show-unsupported")
     args+=("-C${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-nodebug.cmake")
 ;;
+generic-no-random_device)
+    export CC=clang
+    export CXX=clang++
+    args+=("-DLLVM_LIT_ARGS=-sv --show-unsupported")
+    args+=("-C${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-no-random_device.cmake")
+;;
 x86_64-apple-system)
     export CC=clang
     export CXX=clang++

diff  --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index dfdc0bae7a29..14d4dcb17943 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -73,7 +73,8 @@
   '_LIBCPP_HAS_THREAD_API_PTHREAD': 'libcpp-has-thread-api-pthread',
   '_LIBCPP_NO_VCRUNTIME': 'libcpp-no-vcruntime',
   '_LIBCPP_ABI_VERSION': 'libcpp-abi-version',
-  '_LIBCPP_ABI_UNSTABLE': 'libcpp-abi-unstable'
+  '_LIBCPP_ABI_UNSTABLE': 'libcpp-abi-unstable',
+  '_LIBCPP_HAS_NO_RANDOM_DEVICE': 'libcpp-has-no-random-device',
 }
 for macro, feature in macros.items():
   DEFAULT_FEATURES += [


        


More information about the libcxx-commits mailing list