Path: blob/main/contrib/llvm-project/libcxx/src/random.cpp
35154 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <__config>910#if defined(_LIBCPP_USING_WIN32_RANDOM)11// Must be defined before including stdlib.h to enable rand_s().12# define _CRT_RAND_S13#endif // defined(_LIBCPP_USING_WIN32_RANDOM)1415#include <__system_error/system_error.h>16#include <limits>17#include <random>1819#include <errno.h>20#include <stdio.h>21#include <stdlib.h>2223#if defined(_LIBCPP_USING_GETENTROPY)24# include <sys/random.h>25#elif defined(_LIBCPP_USING_DEV_RANDOM)26# include <fcntl.h>27# include <unistd.h>28# if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>)29# include <linux/random.h>30# include <sys/ioctl.h>31# endif32#elif defined(_LIBCPP_USING_NACL_RANDOM)33# include <nacl/nacl_random.h>34#elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)35# include <zircon/syscalls.h>36#endif3738_LIBCPP_BEGIN_NAMESPACE_STD3940#if defined(_LIBCPP_USING_GETENTROPY)4142random_device::random_device(const string& __token) {43if (__token != "/dev/urandom")44__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());45}4647random_device::~random_device() {}4849unsigned random_device::operator()() {50unsigned r;51size_t n = sizeof(r);52int err = getentropy(&r, n);53if (err)54__throw_system_error(errno, "random_device getentropy failed");55return r;56}5758#elif defined(_LIBCPP_USING_ARC4_RANDOM)5960random_device::random_device(const string&) {}6162random_device::~random_device() {}6364unsigned random_device::operator()() { return arc4random(); }6566#elif defined(_LIBCPP_USING_DEV_RANDOM)6768random_device::random_device(const string& __token) : __f_(open(__token.c_str(), O_RDONLY)) {69if (__f_ < 0)70__throw_system_error(errno, ("random_device failed to open " + __token).c_str());71}7273random_device::~random_device() { close(__f_); }7475unsigned random_device::operator()() {76unsigned r;77size_t n = sizeof(r);78char* p = reinterpret_cast<char*>(&r);79while (n > 0) {80ssize_t s = read(__f_, p, n);81if (s == 0)82__throw_system_error(ENOMSG, "random_device got EOF");83if (s == -1) {84if (errno != EINTR)85__throw_system_error(errno, "random_device got an unexpected error");86continue;87}88n -= static_cast<size_t>(s);89p += static_cast<size_t>(s);90}91return r;92}9394#elif defined(_LIBCPP_USING_NACL_RANDOM)9596random_device::random_device(const string& __token) {97if (__token != "/dev/urandom")98__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());99int error = nacl_secure_random_init();100if (error)101__throw_system_error(error, ("random device failed to open " + __token).c_str());102}103104random_device::~random_device() {}105106unsigned random_device::operator()() {107unsigned r;108size_t n = sizeof(r);109size_t bytes_written;110int error = nacl_secure_random(&r, n, &bytes_written);111if (error != 0)112__throw_system_error(error, "random_device failed getting bytes");113else if (bytes_written != n)114__throw_runtime_error("random_device failed to obtain enough bytes");115return r;116}117118#elif defined(_LIBCPP_USING_WIN32_RANDOM)119120random_device::random_device(const string& __token) {121if (__token != "/dev/urandom")122__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());123}124125random_device::~random_device() {}126127unsigned random_device::operator()() {128unsigned r;129errno_t err = rand_s(&r);130if (err)131__throw_system_error(err, "random_device rand_s failed.");132return r;133}134135#elif defined(_LIBCPP_USING_FUCHSIA_CPRNG)136137random_device::random_device(const string& __token) {138if (__token != "/dev/urandom")139__throw_system_error(ENOENT, ("random device not supported " + __token).c_str());140}141142random_device::~random_device() {}143144unsigned random_device::operator()() {145// Implicitly link against the vDSO system call ABI without146// requiring the final link to specify -lzircon explicitly when147// statically linking libc++.148# pragma comment(lib, "zircon")149150// The system call cannot fail. It returns only when the bits are ready.151unsigned r;152_zx_cprng_draw(&r, sizeof(r));153return r;154}155156#else157# error "Random device not implemented for this architecture"158#endif159160double random_device::entropy() const noexcept {161#if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT)162int ent;163if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0)164return 0;165166if (ent < 0)167return 0;168169if (ent > std::numeric_limits<result_type>::digits)170return std::numeric_limits<result_type>::digits;171172return ent;173#elif defined(_LIBCPP_USING_ARC4_RANDOM) || defined(_LIBCPP_USING_FUCHSIA_CPRNG)174return std::numeric_limits<result_type>::digits;175#else176return 0;177#endif178}179180_LIBCPP_END_NAMESPACE_STD181182183