1 // random -*- C++ -*- 2 3 // Copyright (C) 2012-2018 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 #define _GLIBCXX_USE_CXX11_ABI 1 26 #include <random> 27 28 #ifdef _GLIBCXX_USE_C99_STDINT_TR1 29 30 #if defined __i386__ || defined __x86_64__ 31 # include <cpuid.h> 32 #endif 33 34 #include <cerrno> 35 #include <cstdio> 36 37 #ifdef _GLIBCXX_HAVE_UNISTD_H 38 # include <unistd.h> 39 #endif 40 41 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H 42 # include <sys/ioctl.h> 43 #endif 44 45 #ifdef _GLIBCXX_HAVE_LINUX_TYPES_H 46 # include <linux/types.h> 47 #endif 48 49 #ifdef _GLIBCXX_HAVE_LINUX_RANDOM_H 50 # include <linux/random.h> 51 #endif 52 53 namespace std _GLIBCXX_VISIBILITY(default) 54 { 55 namespace 56 { 57 static unsigned long _M_strtoul(const std::string & __str)58 _M_strtoul(const std::string& __str) 59 { 60 unsigned long __ret = 5489UL; 61 if (__str != "mt19937") 62 { 63 const char* __nptr = __str.c_str(); 64 char* __endptr; 65 __ret = std::strtoul(__nptr, &__endptr, 0); 66 if (*__nptr == '\0' || *__endptr != '\0') 67 std::__throw_runtime_error(__N("random_device::_M_strtoul" 68 "(const std::string&)")); 69 } 70 return __ret; 71 } 72 73 #if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND 74 unsigned int 75 __attribute__ ((target("rdrnd"))) __x86_rdrand(void)76 __x86_rdrand(void) 77 { 78 unsigned int retries = 100; 79 unsigned int val; 80 81 while (__builtin_ia32_rdrand32_step(&val) == 0) 82 if (--retries == 0) 83 std::__throw_runtime_error(__N("random_device::__x86_rdrand(void)")); 84 85 return val; 86 } 87 #endif 88 } 89 90 void _M_init(const std::string & token)91 random_device::_M_init(const std::string& token) 92 { 93 const char *fname = token.c_str(); 94 95 if (token == "default") 96 { 97 #if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND 98 unsigned int eax, ebx, ecx, edx; 99 // Check availability of cpuid and, for now at least, also the 100 // CPU signature for Intel's 101 if (__get_cpuid_max(0, &ebx) > 0 && ebx == signature_INTEL_ebx) 102 { 103 __cpuid(1, eax, ebx, ecx, edx); 104 if (ecx & bit_RDRND) 105 { 106 _M_file = nullptr; 107 return; 108 } 109 } 110 #endif 111 112 fname = "/dev/urandom"; 113 } 114 else if (token != "/dev/urandom" && token != "/dev/random") 115 fail: 116 std::__throw_runtime_error(__N("random_device::" 117 "random_device(const std::string&)")); 118 119 _M_file = static_cast<void*>(std::fopen(fname, "rb")); 120 if (!_M_file) 121 goto fail; 122 } 123 124 void _M_init_pretr1(const std::string & token)125 random_device::_M_init_pretr1(const std::string& token) 126 { 127 _M_mt.seed(_M_strtoul(token)); 128 } 129 130 void _M_fini()131 random_device::_M_fini() 132 { 133 if (_M_file) 134 std::fclose(static_cast<FILE*>(_M_file)); 135 } 136 137 random_device::result_type _M_getval()138 random_device::_M_getval() 139 { 140 #if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND 141 if (!_M_file) 142 return __x86_rdrand(); 143 #endif 144 145 result_type __ret; 146 void* p = &__ret; 147 size_t n = sizeof(result_type); 148 #ifdef _GLIBCXX_HAVE_UNISTD_H 149 do 150 { 151 const int e = read(fileno(static_cast<FILE*>(_M_file)), p, n); 152 if (e > 0) 153 { 154 n -= e; 155 p = static_cast<char*>(p) + e; 156 } 157 else if (e != -1 || errno != EINTR) 158 __throw_runtime_error(__N("random_device could not be read")); 159 } 160 while (n > 0); 161 #else 162 const size_t e = std::fread(p, n, 1, static_cast<FILE*>(_M_file)); 163 if (e != 1) 164 __throw_runtime_error(__N("random_device could not be read")); 165 #endif 166 167 return __ret; 168 } 169 170 random_device::result_type _M_getval_pretr1()171 random_device::_M_getval_pretr1() 172 { 173 return _M_mt(); 174 } 175 176 double _M_getentropy() const177 random_device::_M_getentropy() const noexcept 178 { 179 #if defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT 180 if (!_M_file) 181 return 0.0; 182 183 const int fd = fileno(static_cast<FILE*>(_M_file)); 184 if (fd < 0) 185 return 0.0; 186 187 int ent; 188 if (ioctl(fd, RNDGETENTCNT, &ent) < 0) 189 return 0.0; 190 191 if (ent < 0) 192 return 0.0; 193 194 const int max = sizeof(result_type) * __CHAR_BIT__; 195 if (ent > max) 196 ent = max; 197 198 return static_cast<double>(ent); 199 #else 200 return 0.0; 201 #endif 202 } 203 204 template class mersenne_twister_engine< 205 uint_fast32_t, 206 32, 624, 397, 31, 207 0x9908b0dfUL, 11, 208 0xffffffffUL, 7, 209 0x9d2c5680UL, 15, 210 0xefc60000UL, 18, 1812433253UL>; 211 } 212 #endif 213