3 // Copyright (C) 2012-2023 Free Software Foundation, Inc.
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)
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.
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.
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/>.
25 #define _GLIBCXX_USE_CXX11_ABI 1
26 #define _CRT_RAND_S // define this before including <stdlib.h> to get rand_s
29 #include <system_error>
31 #ifdef _GLIBCXX_USE_C99_STDINT_TR1
33 #if defined __i386__ || defined __x86_64__
35 # ifdef _GLIBCXX_X86_RDRAND
38 # ifdef _GLIBCXX_X86_RDSEED
41 #elif defined __powerpc64__ && defined __BUILTIN_CPU_SUPPORTS__
47 #include <cctype> // For std::isdigit.
49 #if defined _GLIBCXX_HAVE_UNISTD_H && defined _GLIBCXX_HAVE_FCNTL_H
52 // Use POSIX open, close, read etc. instead of ISO fopen, fclose, fread
53 # define USE_POSIX_FILE_IO
56 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H
57 # include <sys/ioctl.h>
60 #ifdef _GLIBCXX_HAVE_LINUX_TYPES_H
61 # include <linux/types.h>
64 #ifdef _GLIBCXX_HAVE_LINUX_RANDOM_H
65 # include <linux/random.h>
68 #ifdef _GLIBCXX_USE_CRT_RAND_S
72 #ifdef _GLIBCXX_HAVE_GETENTROPY
76 #if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM \
77 || _GLIBCXX_HAVE_GETENTROPY
78 // The OS provides a source of randomness we can use.
79 # pragma GCC poison _M_mt
80 #elif defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
81 // Hardware instructions might be available, but use cpuid checks at runtime.
82 # pragma GCC poison _M_mt
83 // If the runtime cpuid checks fail we'll use a linear congruential engine.
86 // Use the mt19937 member of the union, as in previous GCC releases.
87 # define USE_MT19937 1
94 namespace std
_GLIBCXX_VISIBILITY(default)
100 __throw_syserr([[maybe_unused
]] int e
, [[maybe_unused
]] const char* msg
)
101 { _GLIBCXX_THROW_OR_ABORT(system_error(e
, std::generic_category(), msg
)); }
105 __attribute__ ((target("rdrnd")))
108 unsigned int retries
= 100;
111 while (__builtin_ia32_rdrand32_step(&val
) == 0) [[__unlikely__
]]
113 std::__throw_runtime_error(__N("random_device: rdrand failed"));
121 __attribute__ ((target("rdseed")))
122 __x86_rdseed(void* fallback
)
124 unsigned int retries
= 100;
127 while (__builtin_ia32_rdseed_si_step(&val
) == 0) [[__unlikely__
]]
131 if (auto f
= reinterpret_cast<unsigned int(*)(void*)>(fallback
))
133 std::__throw_runtime_error(__N("random_device: rdseed failed"));
135 __builtin_ia32_pause();
143 __attribute__ ((target("rdseed,rdrnd")))
144 __x86_rdseed_rdrand(void*)
146 return __x86_rdseed(reinterpret_cast<void*>(&__x86_rdrand
));
153 __attribute__((target("cpu=power9")))
156 const uint64_t failed
= -1;
157 unsigned int retries
= 10;
158 uint64_t val
= __builtin_darn();
159 while (val
== failed
) [[__unlikely__
]]
162 std::__throw_runtime_error(__N("random_device: darn failed"));
163 val
= __builtin_darn();
165 return (uint32_t)val
;
169 #ifdef _GLIBCXX_USE_CRT_RAND_S
171 __winxp_rand_s(void*)
174 if (::rand_s(&val
) != 0)
175 std::__throw_runtime_error(__N("random_device: rand_s failed"));
180 #ifdef _GLIBCXX_HAVE_GETENTROPY
182 __libc_getentropy(void*)
185 if (::getentropy(&val
, sizeof(val
)) != 0)
186 std::__throw_runtime_error(__N("random_device: getentropy failed"));
191 #ifdef _GLIBCXX_HAVE_ARC4RANDOM
193 __libc_arc4random(void*)
195 return ::arc4random();
200 // TODO: use this to seed std::mt19937 engine too.
202 bad_seed(void* p
) noexcept
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
)
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
)
222 // Same as std::minstd_rand0 but using unsigned not uint_fast32_t.
224 = linear_congruential_engine
<unsigned, 16807UL, 0UL, 2147483647UL>;
227 construct_lcg_at(void* addr
) noexcept
229 return ::new(addr
) lcg_type(bad_seed(addr
));
233 destroy_lcg_at(void* addr
) noexcept
235 static_cast<lcg_type
*>(addr
)->~lcg_type();
239 __lcg(void* ptr
) noexcept
241 auto& lcg
= *static_cast<lcg_type
*>(ptr
);
246 enum Which
: unsigned {
247 device_file
= 1, prng
= 2, rand_s
= 4, getentropy
= 8, arc4random
= 16,
248 rdseed
= 64, rdrand
= 128, darn
= 256,
253 operator|(Which l
, Which r
) noexcept
254 { return Which(unsigned(l
) | unsigned(r
)); }
257 which_source(random_device::result_type (*func
[[maybe_unused
]])(void*),
258 void* file
[[maybe_unused
]])
260 #ifdef _GLIBCXX_USE_CRT_RAND_S
261 if (func
== &__winxp_rand_s
)
267 if (func
== &__x86_rdseed_rdrand
)
270 if (func
== &__x86_rdseed
)
275 if (func
== &__x86_rdrand
)
280 if (func
== &__ppc_darn
)
284 #ifdef _GLIBCXX_USE_DEV_RANDOM
289 #ifdef _GLIBCXX_HAVE_ARC4RANDOM
290 if (func
== __libc_arc4random
)
294 #ifdef _GLIBCXX_HAVE_GETENTROPY
295 if (func
== __libc_getentropy
)
308 return any
; // should be unreachable
313 random_device::_M_init(const std::string
& token
)
316 // If no real random device is supported then use the mt19937 engine.
317 _M_init_pretr1(token
);
325 const char* fname
[[gnu::unused
]] = nullptr;
329 if (token
== "default")
332 fname
= "/dev/urandom";
335 else if (token
== "rdseed")
339 else if (token
== "rdrand" || token
== "rdrnd")
343 else if (token
== "darn")
346 #if defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
347 else if (token
== "hw" || token
== "hardware")
348 which
= rdrand
| rdseed
| darn
;
350 #ifdef _GLIBCXX_USE_CRT_RAND_S
351 else if (token
== "rand_s")
353 #endif // _GLIBCXX_USE_CRT_RAND_S
354 #ifdef _GLIBCXX_HAVE_GETENTROPY
355 else if (token
== "getentropy")
357 #endif // _GLIBCXX_HAVE_GETENTROPY
358 #ifdef _GLIBCXX_HAVE_ARC4RANDOM
359 else if (token
== "arc4random")
361 #endif // _GLIBCXX_HAVE_ARC4RANDOM
362 #ifdef _GLIBCXX_USE_DEV_RANDOM
363 else if (token
== "/dev/urandom" || token
== "/dev/random")
365 fname
= token
.c_str();
368 #endif // _GLIBCXX_USE_DEV_RANDOM
370 else if (token
== "prng")
374 std::__throw_syserr(EINVAL
, __N("random_device::random_device"
375 "(const std::string&):"
376 " unsupported token"));
378 #ifdef _GLIBCXX_USE_CRT_RAND_S
381 _M_func
= &__winxp_rand_s
;
384 #endif // _GLIBCXX_USE_CRT_RAND_S
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
))
395 // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18]
396 __cpuid_count(7, 0, eax
, ebx
, ecx
, edx
);
397 if (ebx
& bit_RDSEED
)
400 // CPUID.01H:ECX.RDRAND[bit 30]
401 __cpuid(1, eax
, ebx
, ecx
, edx
);
404 _M_func
= &__x86_rdseed_rdrand
;
408 _M_func
= &__x86_rdseed
;
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
))
424 // CPUID.01H:ECX.RDRAND[bit 30]
425 __cpuid(1, eax
, ebx
, ecx
, edx
);
428 _M_func
= &__x86_rdrand
;
438 if (__builtin_cpu_supports("darn"))
440 _M_func
= &__ppc_darn
;
446 #ifdef _GLIBCXX_HAVE_ARC4RANDOM
447 if (which
& arc4random
)
449 _M_func
= &__libc_arc4random
;
452 #endif // _GLIBCXX_HAVE_ARC4RANDOM
454 #ifdef _GLIBCXX_HAVE_GETENTROPY
455 if (which
& getentropy
)
458 if (::getentropy(&i
, sizeof(i
)) == 0) // On linux the syscall can fail.
460 _M_func
= &__libc_getentropy
;
464 #endif // _GLIBCXX_HAVE_GETENTROPY
466 #ifdef _GLIBCXX_USE_DEV_RANDOM
467 if (which
& device_file
)
469 #ifdef USE_POSIX_FILE_IO
470 _M_fd
= ::open(fname
, O_RDONLY
);
473 // Set _M_file to non-null so that _M_fini() will do clean up.
477 #else // USE_POSIX_FILE_IO
478 _M_file
= static_cast<void*>(std::fopen(fname
, "rb"));
481 #endif // USE_POSIX_FILE_IO
483 #endif // _GLIBCXX_USE_DEV_RANDOM
486 // Either "prng" was requested explicitly, or "default" was requested
487 // but nothing above worked, use a PRNG.
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
);
498 std::__throw_runtime_error(
499 __N("random_device::random_device(const std::string&):"
500 " device not available"));
501 #endif // USE_MT19937
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++.
507 random_device::_M_init_pretr1(const std::string
& token
)
510 unsigned long seed
= 5489UL;
511 if (token
!= "default" && token
!= "mt19937" && token
!= "prng")
513 const char* nptr
= token
.c_str();
515 seed
= std::strtoul(nptr
, &endptr
, 0);
516 if (*nptr
== '\0' || *endptr
!= '\0')
517 std::__throw_syserr(EINVAL
, __N("random_device::_M_init_pretr1"
518 "(const std::string&)"));
522 // Convert old default token "mt19937" or numeric seed tokens to "default".
523 if (token
== "mt19937" || std::isdigit((unsigned char)token
[0]))
530 // Called by old ABI version of random_device::_M_init(const std::string&).
532 random_device::_M_init(const char* s
, size_t len
)
534 const std::string
token(s
, len
);
536 _M_init_pretr1(token
);
543 random_device::_M_fini()
545 // _M_file == nullptr means no resources to free.
550 if (_M_func
== &__lcg
)
552 destroy_lcg_at(_M_file
);
557 #ifdef _GLIBCXX_USE_DEV_RANDOM
558 #ifdef USE_POSIX_FILE_IO
562 std::fclose(static_cast<FILE*>(_M_file
));
568 random_device::result_type
569 random_device::_M_getval()
576 return _M_func(_M_file
);
580 size_t n
= sizeof(result_type
);
581 #ifdef USE_POSIX_FILE_IO
584 const int e
= ::read(_M_fd
, p
, n
);
588 p
= static_cast<char*>(p
) + e
;
590 else if (e
!= -1 || errno
!= EINTR
)
591 __throw_syserr(errno
, __N("random_device could not be read"));
594 #else // USE_POSIX_FILE_IO
595 const size_t e
= std::fread(p
, n
, 1, static_cast<FILE*>(_M_file
));
597 __throw_runtime_error(__N("random_device could not be read"));
598 #endif // USE_POSIX_FILE_IO
601 #endif // USE_MT19937
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
607 random_device::_M_getval_pretr1()
608 { return _M_getval(); }
611 random_device::_M_getentropy() const noexcept
613 const int max
= sizeof(result_type
) * __CHAR_BIT__
;
615 switch(which_source(_M_func
, _M_file
))
634 #if defined _GLIBCXX_USE_DEV_RANDOM \
635 && defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT
637 #ifdef USE_POSIX_FILE_IO
638 const int fd
= _M_fd
;
640 const int fd
= ::fileno(static_cast<FILE*>(_M_file
));
646 if (::ioctl(fd
, RNDGETENTCNT
, &ent
) < 0)
655 return static_cast<double>(ent
);
658 #endif // _GLIBCXX_USE_DEV_RANDOM && _GLIBCXX_HAVE_SYS_IOCTL_H && RNDGETENTCNT
662 template class mersenne_twister_engine
<
668 0xefc60000UL
, 18, 1812433253UL>;
669 #endif // USE_MT19937
673 linear_congruential_engine
<unsigned, 16807UL, 0UL, 2147483647UL>;
674 template struct __detail::_Mod
<unsigned, 2147483647UL, 16807UL, 0UL>;
677 #endif // _GLIBCXX_USE_C99_STDINT_TR1