1 // random -*- C++ -*- 2 3 // Copyright (C) 2012-2022 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 #elif defined __powerpc64__ && defined __BUILTIN_CPU_SUPPORTS__ 41 # define USE_DARN 1 42 #endif 43 44 #include <cerrno> 45 #include <cstdio> 46 #include <cctype> // For std::isdigit. 47 48 #if defined _GLIBCXX_HAVE_UNISTD_H && defined _GLIBCXX_HAVE_FCNTL_H 49 # include <unistd.h> 50 # include <fcntl.h> 51 // Use POSIX open, close, read etc. instead of ISO fopen, fclose, fread 52 # define USE_POSIX_FILE_IO 53 #endif 54 55 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H 56 # include <sys/ioctl.h> 57 #endif 58 59 #ifdef _GLIBCXX_HAVE_LINUX_TYPES_H 60 # include <linux/types.h> 61 #endif 62 63 #ifdef _GLIBCXX_HAVE_LINUX_RANDOM_H 64 # include <linux/random.h> 65 #endif 66 67 #ifdef _GLIBCXX_USE_CRT_RAND_S 68 # include <stdlib.h> 69 #endif 70 71 #ifdef _GLIBCXX_HAVE_GETENTROPY 72 # include <unistd.h> 73 #endif 74 75 #if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM \ 76 || _GLIBCXX_HAVE_GETENTROPY 77 // The OS provides a source of randomness we can use. 78 # pragma GCC poison _M_mt 79 #elif defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN 80 // Hardware instructions might be available, but use cpuid checks at runtime. 81 # pragma GCC poison _M_mt 82 // If the runtime cpuid checks fail we'll use a linear congruential engine. 83 # define USE_LCG 1 84 #else 85 // Use the mt19937 member of the union, as in previous GCC releases. 86 # define USE_MT19937 1 87 #endif 88 89 #ifdef USE_LCG 90 # include <chrono> 91 #endif 92 93 namespace std _GLIBCXX_VISIBILITY(default) 94 { 95 namespace 96 { 97 #if USE_RDRAND 98 unsigned int 99 __attribute__ ((noinline)) 100 # ifndef __clang__ 101 __attribute__ ((target("rdrnd"))) 102 # endif __x86_rdrand(void *)103 __x86_rdrand(void*) 104 { 105 unsigned int retries = 100; 106 unsigned int val; 107 108 while (__builtin_ia32_rdrand32_step(&val) == 0) [[__unlikely__]] 109 if (--retries == 0) 110 std::__throw_runtime_error(__N("random_device: rdrand failed")); 111 112 return val; 113 } 114 #endif 115 116 #if USE_RDSEED 117 unsigned int 118 __attribute__ ((noinline)) 119 # ifndef __clang__ 120 __attribute__ ((target("rdseed"))) 121 # endif __x86_rdseed(void * fallback)122 __x86_rdseed(void* fallback) 123 { 124 unsigned int retries = 100; 125 unsigned int val; 126 127 while (__builtin_ia32_rdseed_si_step(&val) == 0) [[__unlikely__]] 128 { 129 if (--retries == 0) 130 { 131 if (auto f = reinterpret_cast<unsigned int(*)(void*)>(fallback)) 132 return f(nullptr); 133 std::__throw_runtime_error(__N("random_device: rdseed failed")); 134 } 135 __builtin_ia32_pause(); 136 } 137 138 return val; 139 } 140 141 #if USE_RDRAND 142 unsigned int 143 __attribute__ ((target("rdseed,rdrnd"))) __x86_rdseed_rdrand(void *)144 __x86_rdseed_rdrand(void*) 145 { 146 return __x86_rdseed(reinterpret_cast<void*>(&__x86_rdrand)); 147 } 148 #endif 149 #endif 150 151 #ifdef USE_DARN 152 unsigned int 153 __attribute__((target("cpu=power9"))) __ppc_darn(void *)154 __ppc_darn(void*) 155 { 156 const uint64_t failed = -1; 157 unsigned int retries = 10; 158 uint64_t val = __builtin_darn(); 159 while (val == failed) [[__unlikely__]] 160 { 161 if (--retries == 0) 162 std::__throw_runtime_error(__N("random_device: darn failed")); 163 val = __builtin_darn(); 164 } 165 return (uint32_t)val; 166 } 167 #endif 168 169 #ifdef _GLIBCXX_USE_CRT_RAND_S 170 unsigned int __winxp_rand_s(void *)171 __winxp_rand_s(void*) 172 { 173 unsigned int val; 174 if (::rand_s(&val) != 0) 175 std::__throw_runtime_error(__N("random_device: rand_s failed")); 176 return val; 177 } 178 #endif 179 180 #ifdef _GLIBCXX_HAVE_GETENTROPY 181 unsigned int __libc_getentropy(void *)182 __libc_getentropy(void*) 183 { 184 unsigned int val; 185 if (::getentropy(&val, sizeof(val)) != 0) 186 std::__throw_runtime_error(__N("random_device: getentropy failed")); 187 return val; 188 } 189 #endif 190 191 #ifdef _GLIBCXX_HAVE_ARC4RANDOM 192 unsigned int __libc_arc4random(void *)193 __libc_arc4random(void*) 194 { 195 return ::arc4random(); 196 } 197 #endif 198 199 #ifdef USE_LCG 200 // TODO: use this to seed std::mt19937 engine too. 201 unsigned bad_seed(void * p)202 bad_seed(void* p) noexcept 203 { 204 // Poor quality seed based on hash of the current time and the address 205 // of the object being seeded. Better than using the same default seed 206 // for every object though. 207 const uint64_t bits[] = { 208 (uint64_t) chrono::system_clock::now().time_since_epoch().count(), 209 (uint64_t) reinterpret_cast<uintptr_t>(p) 210 }; 211 auto bytes = reinterpret_cast<const unsigned char*>(bits); 212 // 32-bit FNV-1a hash 213 uint32_t h = 2166136261u; 214 for (unsigned i = 0; i < sizeof(bits); ++i) 215 { 216 h ^= *bytes++; 217 h *= 16777619u; 218 } 219 return h; 220 } 221 222 // Same as std::minstd_rand0 but using unsigned not uint_fast32_t. 223 using lcg_type 224 = linear_congruential_engine<unsigned, 16807UL, 0UL, 2147483647UL>; 225 226 inline lcg_type* construct_lcg_at(void * addr)227 construct_lcg_at(void* addr) noexcept 228 { 229 return ::new(addr) lcg_type(bad_seed(addr)); 230 } 231 232 inline void destroy_lcg_at(void * addr)233 destroy_lcg_at(void* addr) noexcept 234 { 235 static_cast<lcg_type*>(addr)->~lcg_type(); 236 } 237 238 unsigned int __lcg(void * ptr)239 __lcg(void* ptr) noexcept 240 { 241 auto& lcg = *static_cast<lcg_type*>(ptr); 242 return lcg(); 243 } 244 #endif 245 246 enum Which : unsigned { 247 device_file = 1, prng = 2, rand_s = 4, getentropy = 8, arc4random = 16, 248 rdseed = 64, rdrand = 128, darn = 256, 249 any = 0xffff 250 }; 251 252 constexpr Which operator |(Which l,Which r)253 operator|(Which l, Which r) noexcept 254 { return Which(unsigned(l) | unsigned(r)); } 255 256 inline Which which_source(random_device::result_type (* func)(void *),void * file)257 which_source(random_device::result_type (*func [[maybe_unused]])(void*), 258 void* file [[maybe_unused]]) 259 { 260 #ifdef _GLIBCXX_USE_CRT_RAND_S 261 if (func == &__winxp_rand_s) 262 return rand_s; 263 #endif 264 265 #ifdef USE_RDSEED 266 #ifdef USE_RDRAND 267 if (func == &__x86_rdseed_rdrand) 268 return rdseed; 269 #endif 270 if (func == &__x86_rdseed) 271 return rdseed; 272 #endif 273 274 #ifdef USE_RDRAND 275 if (func == &__x86_rdrand) 276 return rdrand; 277 #endif 278 279 #ifdef USE_DARN 280 if (func == &__ppc_darn) 281 return darn; 282 #endif 283 284 #ifdef _GLIBCXX_USE_DEV_RANDOM 285 if (file != nullptr) 286 return device_file; 287 #endif 288 289 #ifdef _GLIBCXX_HAVE_ARC4RANDOM 290 if (func == __libc_arc4random) 291 return arc4random; 292 #endif 293 294 #ifdef _GLIBCXX_HAVE_GETENTROPY 295 if (func == __libc_getentropy) 296 return getentropy; 297 #endif 298 299 #ifdef USE_LCG 300 if (func == &__lcg) 301 return prng; 302 #endif 303 304 #ifdef USE_MT19937 305 return prng; 306 #endif 307 308 return any; // should be unreachable 309 } 310 } 311 312 void _M_init(const std::string & token)313 random_device::_M_init(const std::string& token) 314 { 315 #ifdef USE_MT19937 316 // If no real random device is supported then use the mt19937 engine. 317 _M_init_pretr1(token); 318 return; 319 #else 320 321 _M_file = nullptr; 322 _M_func = nullptr; 323 _M_fd = -1; 324 325 const char* fname [[gnu::unused]] = nullptr; 326 327 Which which; 328 329 if (token == "default") 330 { 331 which = any; 332 fname = "/dev/urandom"; 333 } 334 #ifdef USE_RDSEED 335 else if (token == "rdseed") 336 which = rdseed; 337 #endif // USE_RDSEED 338 #ifdef USE_RDRAND 339 else if (token == "rdrand" || token == "rdrnd") 340 which = rdrand; 341 #endif // USE_RDRAND 342 #ifdef USE_DARN 343 else if (token == "darn") 344 which = darn; 345 #endif 346 #if defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN 347 else if (token == "hw" || token == "hardware") 348 which = rdrand | rdseed | darn; 349 #endif 350 #ifdef _GLIBCXX_USE_CRT_RAND_S 351 else if (token == "rand_s") 352 which = rand_s; 353 #endif // _GLIBCXX_USE_CRT_RAND_S 354 #ifdef _GLIBCXX_HAVE_GETENTROPY 355 else if (token == "getentropy") 356 which = getentropy; 357 #endif // _GLIBCXX_HAVE_GETENTROPY 358 #ifdef _GLIBCXX_HAVE_ARC4RANDOM 359 else if (token == "arc4random") 360 which = arc4random; 361 #endif // _GLIBCXX_HAVE_ARC4RANDOM 362 #ifdef _GLIBCXX_USE_DEV_RANDOM 363 else if (token == "/dev/urandom" || token == "/dev/random") 364 { 365 fname = token.c_str(); 366 which = device_file; 367 } 368 #endif // _GLIBCXX_USE_DEV_RANDOM 369 #ifdef USE_LCG 370 else if (token == "prng") 371 which = prng; 372 #endif 373 else 374 std::__throw_runtime_error( 375 __N("random_device::random_device(const std::string&):" 376 " unsupported token")); 377 378 #ifdef _GLIBCXX_USE_CRT_RAND_S 379 if (which & rand_s) 380 { 381 _M_func = &__winxp_rand_s; 382 return; 383 } 384 #endif // _GLIBCXX_USE_CRT_RAND_S 385 386 #ifdef USE_RDSEED 387 if (which & rdseed) 388 { 389 unsigned int eax, ebx, ecx, edx; 390 // Check availability of cpuid and, for now at least, also the 391 // CPU signature for Intel and AMD. 392 if (__get_cpuid_max(0, &ebx) > 0 393 && (ebx == signature_INTEL_ebx || ebx == signature_AMD_ebx)) 394 { 395 // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18] 396 __cpuid_count(7, 0, eax, ebx, ecx, edx); 397 if (ebx & bit_RDSEED) 398 { 399 #ifdef USE_RDRAND 400 // CPUID.01H:ECX.RDRAND[bit 30] 401 __cpuid(1, eax, ebx, ecx, edx); 402 if (ecx & bit_RDRND) 403 { 404 _M_func = &__x86_rdseed_rdrand; 405 return; 406 } 407 #endif 408 _M_func = &__x86_rdseed; 409 return; 410 } 411 } 412 } 413 #endif // USE_RDSEED 414 415 #ifdef USE_RDRAND 416 if (which & rdrand) 417 { 418 unsigned int eax, ebx, ecx, edx; 419 // Check availability of cpuid and, for now at least, also the 420 // CPU signature for Intel and AMD. 421 if (__get_cpuid_max(0, &ebx) > 0 422 && (ebx == signature_INTEL_ebx || ebx == signature_AMD_ebx)) 423 { 424 // CPUID.01H:ECX.RDRAND[bit 30] 425 __cpuid(1, eax, ebx, ecx, edx); 426 if (ecx & bit_RDRND) 427 { 428 _M_func = &__x86_rdrand; 429 return; 430 } 431 } 432 } 433 #endif // USE_RDRAND 434 435 #ifdef USE_DARN 436 if (which & darn) 437 { 438 if (__builtin_cpu_supports("darn")) 439 { 440 _M_func = &__ppc_darn; 441 return; 442 } 443 } 444 #endif // USE_DARN 445 446 #ifdef _GLIBCXX_HAVE_ARC4RANDOM 447 if (which & arc4random) 448 { 449 _M_func = &__libc_arc4random; 450 return; 451 } 452 #endif // _GLIBCXX_HAVE_ARC4RANDOM 453 454 #ifdef _GLIBCXX_HAVE_GETENTROPY 455 if (which & getentropy) 456 { 457 unsigned int i; 458 if (::getentropy(&i, sizeof(i)) == 0) // On linux the syscall can fail. 459 { 460 _M_func = &__libc_getentropy; 461 return; 462 } 463 } 464 #endif // _GLIBCXX_HAVE_GETENTROPY 465 466 #ifdef _GLIBCXX_USE_DEV_RANDOM 467 if (which & device_file) 468 { 469 #ifdef USE_POSIX_FILE_IO 470 _M_fd = ::open(fname, O_RDONLY); 471 if (_M_fd != -1) 472 { 473 // Set _M_file to non-null so that _M_fini() will do clean up. 474 _M_file = &_M_fd; 475 return; 476 } 477 #else // USE_POSIX_FILE_IO 478 _M_file = static_cast<void*>(std::fopen(fname, "rb")); 479 if (_M_file) 480 return; 481 #endif // USE_POSIX_FILE_IO 482 } 483 #endif // _GLIBCXX_USE_DEV_RANDOM 484 485 #ifdef USE_LCG 486 // Either "prng" was requested explicitly, or "default" was requested 487 // but nothing above worked, use a PRNG. 488 if (which & prng) 489 { 490 static_assert(sizeof(lcg_type) <= sizeof(_M_fd), ""); 491 static_assert(alignof(lcg_type) <= alignof(_M_fd), ""); 492 _M_file = construct_lcg_at(&_M_fd); 493 _M_func = &__lcg; 494 return; 495 } 496 #endif 497 498 std::__throw_runtime_error( 499 __N("random_device::random_device(const std::string&):" 500 " device not available")); 501 #endif // USE_MT19937 502 } 503 504 // This function is called by _M_init for targets that use mt19937 for 505 // randomness, and by code compiled against old releases of libstdc++. 506 void _M_init_pretr1(const std::string & token)507 random_device::_M_init_pretr1(const std::string& token) 508 { 509 #ifdef USE_MT19937 510 unsigned long seed = 5489UL; 511 if (token != "default" && token != "mt19937" && token != "prng") 512 { 513 const char* nptr = token.c_str(); 514 char* endptr; 515 seed = std::strtoul(nptr, &endptr, 0); 516 if (*nptr == '\0' || *endptr != '\0') 517 std::__throw_runtime_error(__N("random_device::_M_init_pretr1" 518 "(const std::string&)")); 519 } 520 _M_mt.seed(seed); 521 #else 522 // Convert old default token "mt19937" or numeric seed tokens to "default". 523 if (token == "mt19937" || std::isdigit((unsigned char)token[0])) 524 _M_init("default"); 525 else 526 _M_init(token); 527 #endif 528 } 529 530 // Called by old ABI version of random_device::_M_init(const std::string&). 531 void _M_init(const char * s,size_t len)532 random_device::_M_init(const char* s, size_t len) 533 { 534 const std::string token(s, len); 535 #ifdef USE_MT19937 536 _M_init_pretr1(token); 537 #else 538 _M_init(token); 539 #endif 540 } 541 542 void _M_fini()543 random_device::_M_fini() 544 { 545 // _M_file == nullptr means no resources to free. 546 if (!_M_file) 547 return; 548 549 #if USE_LCG 550 if (_M_func == &__lcg) 551 { 552 destroy_lcg_at(_M_file); 553 return; 554 } 555 #endif 556 557 #ifdef _GLIBCXX_USE_DEV_RANDOM 558 #ifdef USE_POSIX_FILE_IO 559 ::close(_M_fd); 560 _M_fd = -1; 561 #else 562 std::fclose(static_cast<FILE*>(_M_file)); 563 #endif 564 _M_file = nullptr; 565 #endif 566 } 567 568 random_device::result_type _M_getval()569 random_device::_M_getval() 570 { 571 #ifdef USE_MT19937 572 return _M_mt(); 573 #else 574 575 if (_M_func) 576 return _M_func(_M_file); 577 578 result_type ret; 579 void* p = &ret; 580 size_t n = sizeof(result_type); 581 #ifdef USE_POSIX_FILE_IO 582 do 583 { 584 const int e = ::read(_M_fd, p, n); 585 if (e > 0) 586 { 587 n -= e; 588 p = static_cast<char*>(p) + e; 589 } 590 else if (e != -1 || errno != EINTR) 591 __throw_runtime_error(__N("random_device could not be read")); 592 } 593 while (n > 0); 594 #else // USE_POSIX_FILE_IO 595 const size_t e = std::fread(p, n, 1, static_cast<FILE*>(_M_file)); 596 if (e != 1) 597 __throw_runtime_error(__N("random_device could not be read")); 598 #endif // USE_POSIX_FILE_IO 599 600 return ret; 601 #endif // USE_MT19937 602 } 603 604 // Only called by code compiled against old releases of libstdc++. 605 // Forward the call to _M_getval() and let it decide what to do. 606 random_device::result_type _M_getval_pretr1()607 random_device::_M_getval_pretr1() 608 { return _M_getval(); } 609 610 double _M_getentropy() const611 random_device::_M_getentropy() const noexcept 612 { 613 const int max = sizeof(result_type) * __CHAR_BIT__; 614 615 switch(which_source(_M_func, _M_file)) 616 { 617 case rdrand: 618 case rdseed: 619 case darn: 620 return (double) max; 621 case arc4random: 622 case getentropy: 623 return (double) max; 624 case rand_s: 625 case prng: 626 return 0.0; 627 case device_file: 628 // handled below 629 break; 630 default: 631 return 0.0; 632 } 633 634 #if defined _GLIBCXX_USE_DEV_RANDOM \ 635 && defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT 636 637 #ifdef USE_POSIX_FILE_IO 638 const int fd = _M_fd; 639 #else 640 const int fd = ::fileno(static_cast<FILE*>(_M_file)); 641 #endif 642 if (fd < 0) 643 return 0.0; 644 645 int ent; 646 if (::ioctl(fd, RNDGETENTCNT, &ent) < 0) 647 return 0.0; 648 649 if (ent < 0) 650 return 0.0; 651 652 if (ent > max) 653 ent = max; 654 655 return static_cast<double>(ent); 656 #else 657 return 0.0; 658 #endif // _GLIBCXX_USE_DEV_RANDOM && _GLIBCXX_HAVE_SYS_IOCTL_H && RNDGETENTCNT 659 } 660 661 #ifdef USE_MT19937 662 template class mersenne_twister_engine< 663 uint_fast32_t, 664 32, 624, 397, 31, 665 0x9908b0dfUL, 11, 666 0xffffffffUL, 7, 667 0x9d2c5680UL, 15, 668 0xefc60000UL, 18, 1812433253UL>; 669 #endif // USE_MT19937 670 671 #ifdef USE_LCG 672 template class 673 linear_congruential_engine<unsigned, 16807UL, 0UL, 2147483647UL>; 674 template struct __detail::_Mod<unsigned, 2147483647UL, 16807UL, 0UL>; 675 #endif 676 } 677 #endif // _GLIBCXX_USE_C99_STDINT_TR1 678