1 // random -*- C++ -*- 2 3 // Copyright (C) 2012-2021 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 #define _CRT_RAND_S // define this before including <stdlib.h> to get rand_s 27 28 #include <random> 29 30 #ifdef _GLIBCXX_USE_C99_STDINT_TR1 31 32 #if defined __i386__ || defined __x86_64__ 33 # include <cpuid.h> 34 # ifdef _GLIBCXX_X86_RDRAND 35 # define USE_RDRAND 1 36 # endif 37 # ifdef _GLIBCXX_X86_RDSEED 38 # define USE_RDSEED 1 39 # endif 40 #endif 41 42 #include <cerrno> 43 #include <cstdio> 44 #include <cctype> // For std::isdigit. 45 46 #if defined _GLIBCXX_HAVE_UNISTD_H && defined _GLIBCXX_HAVE_FCNTL_H 47 # include <unistd.h> 48 # include <fcntl.h> 49 // Use POSIX open, close, read etc. instead of ISO fopen, fclose, fread 50 # define USE_POSIX_FILE_IO 51 #endif 52 53 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H 54 # include <sys/ioctl.h> 55 #endif 56 57 #ifdef _GLIBCXX_HAVE_LINUX_TYPES_H 58 # include <linux/types.h> 59 #endif 60 61 #ifdef _GLIBCXX_HAVE_LINUX_RANDOM_H 62 # include <linux/random.h> 63 #endif 64 65 #ifdef _GLIBCXX_USE_CRT_RAND_S 66 # include <stdlib.h> 67 #endif 68 69 #if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM 70 // The OS provides a source of randomness we can use. 71 # pragma GCC poison _M_mt 72 #elif defined USE_RDRAND || defined USE_RDSEED 73 // Hardware instructions might be available, but use cpuid checks at runtime. 74 # pragma GCC poison _M_mt 75 // If the runtime cpuid checks fail we'll use a linear congruential engine. 76 # define USE_LCG 1 77 #else 78 // Use the mt19937 member of the union, as in previous GCC releases. 79 # define USE_MT19937 1 80 #endif 81 82 #ifdef USE_LCG 83 # include <chrono> 84 #endif 85 86 namespace std _GLIBCXX_VISIBILITY(default) 87 { 88 namespace 89 { 90 #if USE_RDRAND 91 unsigned int 92 __attribute__ ((target("rdrnd"))) __x86_rdrand(void *)93 __x86_rdrand(void*) 94 { 95 unsigned int retries = 100; 96 unsigned int val; 97 98 while (__builtin_ia32_rdrand32_step(&val) == 0) 99 if (--retries == 0) 100 std::__throw_runtime_error(__N("random_device: rdrand failed")); 101 102 return val; 103 } 104 #endif 105 106 #if USE_RDSEED 107 unsigned int 108 __attribute__ ((target("rdseed"))) __x86_rdseed(void * fallback)109 __x86_rdseed(void* fallback) 110 { 111 unsigned int retries = 100; 112 unsigned int val; 113 114 while (__builtin_ia32_rdseed_si_step(&val) == 0) 115 { 116 if (--retries == 0) 117 { 118 if (auto f = reinterpret_cast<unsigned int(*)(void*)>(fallback)) 119 return f(nullptr); 120 std::__throw_runtime_error(__N("random_device: rdseed failed")); 121 } 122 __builtin_ia32_pause(); 123 } 124 125 return val; 126 } 127 128 #if USE_RDRAND 129 unsigned int 130 __attribute__ ((target("rdseed,rdrnd"))) __x86_rdseed_rdrand(void *)131 __x86_rdseed_rdrand(void*) 132 { 133 return __x86_rdseed(reinterpret_cast<void*>(&__x86_rdrand)); 134 } 135 #endif 136 #endif 137 138 #ifdef _GLIBCXX_USE_CRT_RAND_S 139 unsigned int __winxp_rand_s(void *)140 __winxp_rand_s(void*) 141 { 142 unsigned int val; 143 if (::rand_s(&val) != 0) 144 std::__throw_runtime_error(__N("random_device: rand_s failed")); 145 return val; 146 } 147 #endif 148 149 #ifdef USE_LCG 150 // TODO: use this to seed std::mt19937 engine too. 151 unsigned bad_seed(void * p)152 bad_seed(void* p) noexcept 153 { 154 // Poor quality seed based on hash of the current time and the address 155 // of the object being seeded. Better than using the same default seed 156 // for every object though. 157 const uint64_t bits[] = { 158 (uint64_t) chrono::system_clock::now().time_since_epoch().count(), 159 (uint64_t) reinterpret_cast<uintptr_t>(p) 160 }; 161 auto bytes = reinterpret_cast<const unsigned char*>(bits); 162 // 32-bit FNV-1a hash 163 uint32_t h = 2166136261u; 164 for (unsigned i = 0; i < sizeof(bits); ++i) 165 { 166 h ^= *bytes++; 167 h *= 16777619u; 168 } 169 return h; 170 } 171 172 // Same as std::minstd_rand0 but using unsigned not uint_fast32_t. 173 using lcg_type 174 = linear_congruential_engine<unsigned, 16807UL, 0UL, 2147483647UL>; 175 176 inline lcg_type* construct_lcg_at(void * addr)177 construct_lcg_at(void* addr) noexcept 178 { 179 return ::new(addr) lcg_type(bad_seed(addr)); 180 } 181 182 inline void destroy_lcg_at(void * addr)183 destroy_lcg_at(void* addr) noexcept 184 { 185 static_cast<lcg_type*>(addr)->~lcg_type(); 186 } 187 188 unsigned int __lcg(void * ptr)189 __lcg(void* ptr) noexcept 190 { 191 auto& lcg = *static_cast<lcg_type*>(ptr); 192 return lcg(); 193 } 194 #endif 195 } 196 197 void _M_init(const std::string & token)198 random_device::_M_init(const std::string& token) 199 { 200 #ifdef USE_MT19937 201 // If no real random device is supported then use the mt19937 engine. 202 _M_init_pretr1(token); 203 return; 204 #else 205 206 _M_file = nullptr; 207 _M_func = nullptr; 208 _M_fd = -1; 209 210 const char* fname [[gnu::unused]] = nullptr; 211 212 enum { 213 rand_s = 1, rdseed = 2, rdrand = 4, device_file = 8, prng = 16, 214 any = 0xffff 215 } which; 216 217 if (token == "default") 218 { 219 which = any; 220 fname = "/dev/urandom"; 221 } 222 #ifdef USE_RDSEED 223 else if (token == "rdseed") 224 which = rdseed; 225 #endif // USE_RDSEED 226 #ifdef USE_RDRAND 227 else if (token == "rdrand" || token == "rdrnd") 228 which = rdrand; 229 #endif // USE_RDRAND 230 #ifdef _GLIBCXX_USE_CRT_RAND_S 231 else if (token == "rand_s") 232 which = rand_s; 233 #endif // _GLIBCXX_USE_CRT_RAND_S 234 #ifdef _GLIBCXX_USE_DEV_RANDOM 235 else if (token == "/dev/urandom" || token == "/dev/random") 236 { 237 fname = token.c_str(); 238 which = device_file; 239 } 240 #endif // _GLIBCXX_USE_DEV_RANDOM 241 #ifdef USE_LCG 242 else if (token == "prng") 243 which = prng; 244 #endif 245 else 246 std::__throw_runtime_error( 247 __N("random_device::random_device(const std::string&):" 248 " unsupported token")); 249 250 #ifdef _GLIBCXX_USE_CRT_RAND_S 251 if (which & rand_s) 252 { 253 _M_func = &__winxp_rand_s; 254 return; 255 } 256 #endif // _GLIBCXX_USE_CRT_RAND_S 257 258 #ifdef USE_RDSEED 259 if (which & rdseed) 260 { 261 unsigned int eax, ebx, ecx, edx; 262 // Check availability of cpuid and, for now at least, also the 263 // CPU signature for Intel and AMD. 264 if (__get_cpuid_max(0, &ebx) > 0 265 && (ebx == signature_INTEL_ebx || ebx == signature_AMD_ebx)) 266 { 267 // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18] 268 __cpuid_count(7, 0, eax, ebx, ecx, edx); 269 if (ebx & bit_RDSEED) 270 { 271 #ifdef USE_RDRAND 272 // CPUID.01H:ECX.RDRAND[bit 30] 273 __cpuid(1, eax, ebx, ecx, edx); 274 if (ecx & bit_RDRND) 275 { 276 _M_func = &__x86_rdseed_rdrand; 277 return; 278 } 279 #endif 280 _M_func = &__x86_rdseed; 281 return; 282 } 283 } 284 } 285 #endif // USE_RDSEED 286 287 #ifdef USE_RDRAND 288 if (which & rdrand) 289 { 290 unsigned int eax, ebx, ecx, edx; 291 // Check availability of cpuid and, for now at least, also the 292 // CPU signature for Intel and AMD. 293 if (__get_cpuid_max(0, &ebx) > 0 294 && (ebx == signature_INTEL_ebx || ebx == signature_AMD_ebx)) 295 { 296 // CPUID.01H:ECX.RDRAND[bit 30] 297 __cpuid(1, eax, ebx, ecx, edx); 298 if (ecx & bit_RDRND) 299 { 300 _M_func = &__x86_rdrand; 301 return; 302 } 303 } 304 } 305 #endif // USE_RDRAND 306 307 #ifdef _GLIBCXX_USE_DEV_RANDOM 308 if (which & device_file) 309 { 310 #ifdef USE_POSIX_FILE_IO 311 _M_fd = ::open(fname, O_RDONLY); 312 if (_M_fd != -1) 313 { 314 // Set _M_file to non-null so that _M_fini() will do clean up. 315 _M_file = &_M_fd; 316 return; 317 } 318 #else // USE_POSIX_FILE_IO 319 _M_file = static_cast<void*>(std::fopen(fname, "rb")); 320 if (_M_file) 321 return; 322 #endif // USE_POSIX_FILE_IO 323 } 324 #endif // _GLIBCXX_USE_DEV_RANDOM 325 326 #ifdef USE_LCG 327 // Either "prng" was requested explicitly, or "default" was requested 328 // but nothing above worked, use a PRNG. 329 if (which & prng) 330 { 331 static_assert(sizeof(lcg_type) <= sizeof(_M_fd), ""); 332 static_assert(alignof(lcg_type) <= alignof(_M_fd), ""); 333 _M_file = construct_lcg_at(&_M_fd); 334 _M_func = &__lcg; 335 return; 336 } 337 #endif 338 339 std::__throw_runtime_error( 340 __N("random_device::random_device(const std::string&):" 341 " device not available")); 342 #endif // USE_MT19937 343 } 344 345 // This function is called by _M_init for targets that use mt19937 for 346 // randomness, and by code compiled against old releases of libstdc++. 347 void _M_init_pretr1(const std::string & token)348 random_device::_M_init_pretr1(const std::string& token) 349 { 350 #ifdef USE_MT19937 351 unsigned long seed = 5489UL; 352 if (token != "default" && token != "mt19937" && token != "prng") 353 { 354 const char* nptr = token.c_str(); 355 char* endptr; 356 seed = std::strtoul(nptr, &endptr, 0); 357 if (*nptr == '\0' || *endptr != '\0') 358 std::__throw_runtime_error(__N("random_device::_M_init_pretr1" 359 "(const std::string&)")); 360 } 361 _M_mt.seed(seed); 362 #else 363 // Convert old default token "mt19937" or numeric seed tokens to "default". 364 if (token == "mt19937" || std::isdigit((unsigned char)token[0])) 365 _M_init("default"); 366 else 367 _M_init(token); 368 #endif 369 } 370 371 // Called by old ABI version of random_device::_M_init(const std::string&). 372 void _M_init(const char * s,size_t len)373 random_device::_M_init(const char* s, size_t len) 374 { 375 const std::string token(s, len); 376 #ifdef USE_MT19937 377 _M_init_pretr1(token); 378 #else 379 _M_init(token); 380 #endif 381 } 382 383 void _M_fini()384 random_device::_M_fini() 385 { 386 // _M_file == nullptr means no resources to free. 387 if (!_M_file) 388 return; 389 390 #if USE_LCG 391 if (_M_func == &__lcg) 392 { 393 destroy_lcg_at(_M_file); 394 return; 395 } 396 #endif 397 398 #ifdef USE_POSIX_FILE_IO 399 ::close(_M_fd); 400 _M_fd = -1; 401 #else 402 std::fclose(static_cast<FILE*>(_M_file)); 403 #endif 404 _M_file = nullptr; 405 } 406 407 random_device::result_type _M_getval()408 random_device::_M_getval() 409 { 410 #ifdef USE_MT19937 411 return _M_mt(); 412 #else 413 414 if (_M_func) 415 return _M_func(_M_file); 416 417 result_type ret; 418 void* p = &ret; 419 size_t n = sizeof(result_type); 420 #ifdef USE_POSIX_FILE_IO 421 do 422 { 423 const int e = ::read(_M_fd, p, n); 424 if (e > 0) 425 { 426 n -= e; 427 p = static_cast<char*>(p) + e; 428 } 429 else if (e != -1 || errno != EINTR) 430 __throw_runtime_error(__N("random_device could not be read")); 431 } 432 while (n > 0); 433 #else // USE_POSIX_FILE_IO 434 const size_t e = std::fread(p, n, 1, static_cast<FILE*>(_M_file)); 435 if (e != 1) 436 __throw_runtime_error(__N("random_device could not be read")); 437 #endif // USE_POSIX_FILE_IO 438 439 return ret; 440 #endif // USE_MT19937 441 } 442 443 // Only called by code compiled against old releases of libstdc++. 444 // Forward the call to _M_getval() and let it decide what to do. 445 random_device::result_type _M_getval_pretr1()446 random_device::_M_getval_pretr1() 447 { return _M_getval(); } 448 449 double _M_getentropy() const450 random_device::_M_getentropy() const noexcept 451 { 452 #if defined _GLIBCXX_USE_DEV_RANDOM \ 453 && defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT 454 if (!_M_file) 455 return 0.0; 456 457 #ifdef USE_POSIX_FILE_IO 458 const int fd = _M_fd; 459 #else 460 const int fd = ::fileno(static_cast<FILE*>(_M_file)); 461 #endif 462 if (fd < 0) 463 return 0.0; 464 465 int ent; 466 if (::ioctl(fd, RNDGETENTCNT, &ent) < 0) 467 return 0.0; 468 469 if (ent < 0) 470 return 0.0; 471 472 const int max = sizeof(result_type) * __CHAR_BIT__; 473 if (ent > max) 474 ent = max; 475 476 return static_cast<double>(ent); 477 #else 478 return 0.0; 479 #endif // _GLIBCXX_USE_DEV_RANDOM && _GLIBCXX_HAVE_SYS_IOCTL_H && RNDGETENTCNT 480 } 481 482 #ifdef USE_MT19937 483 template class mersenne_twister_engine< 484 uint_fast32_t, 485 32, 624, 397, 31, 486 0x9908b0dfUL, 11, 487 0xffffffffUL, 7, 488 0x9d2c5680UL, 15, 489 0xefc60000UL, 18, 1812433253UL>; 490 #endif // USE_MT19937 491 492 #ifdef USE_LCG 493 template class 494 linear_congruential_engine<unsigned, 16807UL, 0UL, 2147483647UL>; 495 template struct __detail::_Mod<unsigned, 2147483647UL, 16807UL, 0UL>; 496 #endif 497 } 498 #endif // _GLIBCXX_USE_C99_STDINT_TR1 499