3 // Copyright (C) 2012-2024 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 #if defined __i386__ || defined __x86_64__
33 # ifdef _GLIBCXX_X86_RDRAND
36 # ifdef _GLIBCXX_X86_RDSEED
39 #elif defined __powerpc64__ && defined __BUILTIN_CPU_SUPPORTS__
45 #include <cctype> // For std::isdigit.
47 #if defined _GLIBCXX_HAVE_UNISTD_H && defined _GLIBCXX_HAVE_FCNTL_H
50 // Use POSIX open, close, read etc. instead of ISO fopen, fclose, fread
51 # define USE_POSIX_FILE_IO
54 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H
55 # include <sys/ioctl.h>
58 #ifdef _GLIBCXX_HAVE_LINUX_TYPES_H
59 # include <linux/types.h>
62 #ifdef _GLIBCXX_HAVE_LINUX_RANDOM_H
63 # include <linux/random.h>
66 #ifdef _GLIBCXX_USE_CRT_RAND_S
70 #ifdef _GLIBCXX_HAVE_GETENTROPY
74 #if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM \
75 || _GLIBCXX_HAVE_GETENTROPY
76 // The OS provides a source of randomness we can use.
77 # pragma GCC poison _M_mt
78 #elif defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
79 // Hardware instructions might be available, but use cpuid checks at runtime.
80 # pragma GCC poison _M_mt
81 // If the runtime cpuid checks fail we'll use a linear congruential engine.
84 // Use the mt19937 member of the union, as in previous GCC releases.
85 # define USE_MT19937 1
92 namespace std
_GLIBCXX_VISIBILITY(default)
98 __throw_syserr([[maybe_unused
]] int e
, [[maybe_unused
]] const char* msg
)
99 { _GLIBCXX_THROW_OR_ABORT(system_error(e
, std::generic_category(), msg
)); }
103 __attribute__ ((target("rdrnd")))
106 unsigned int retries
= 100;
109 while (__builtin_ia32_rdrand32_step(&val
) == 0) [[__unlikely__
]]
111 std::__throw_runtime_error(__N("random_device: rdrand failed"));
119 __attribute__ ((target("rdseed")))
120 __x86_rdseed(void* fallback
)
122 unsigned int retries
= 100;
125 while (__builtin_ia32_rdseed_si_step(&val
) == 0) [[__unlikely__
]]
129 if (auto f
= reinterpret_cast<unsigned int(*)(void*)>(fallback
))
131 std::__throw_runtime_error(__N("random_device: rdseed failed"));
133 __builtin_ia32_pause();
141 __attribute__ ((target("rdseed,rdrnd")))
142 __x86_rdseed_rdrand(void*)
144 return __x86_rdseed(reinterpret_cast<void*>(&__x86_rdrand
));
151 __attribute__((target("cpu=power9")))
154 const uint64_t failed
= -1;
155 unsigned int retries
= 10;
156 uint64_t val
= __builtin_darn();
157 while (val
== failed
) [[__unlikely__
]]
160 std::__throw_runtime_error(__N("random_device: darn failed"));
161 val
= __builtin_darn();
163 return (uint32_t)val
;
167 #ifdef _GLIBCXX_USE_CRT_RAND_S
169 __winxp_rand_s(void*)
172 if (::rand_s(&val
) != 0)
173 std::__throw_runtime_error(__N("random_device: rand_s failed"));
178 #ifdef _GLIBCXX_HAVE_GETENTROPY
180 __libc_getentropy(void*)
183 if (::getentropy(&val
, sizeof(val
)) != 0)
184 std::__throw_runtime_error(__N("random_device: getentropy failed"));
189 #ifdef _GLIBCXX_HAVE_ARC4RANDOM
191 __libc_arc4random(void*)
193 return ::arc4random();
198 // TODO: use this to seed std::mt19937 engine too.
200 bad_seed(void* p
) noexcept
202 // Poor quality seed based on hash of the current time and the address
203 // of the object being seeded. Better than using the same default seed
204 // for every object though.
205 const uint64_t bits
[] = {
206 (uint64_t) chrono::system_clock::now().time_since_epoch().count(),
207 (uint64_t) reinterpret_cast<uintptr_t>(p
)
209 auto bytes
= reinterpret_cast<const unsigned char*>(bits
);
210 // 32-bit FNV-1a hash
211 uint32_t h
= 2166136261u;
212 for (unsigned i
= 0; i
< sizeof(bits
); ++i
)
220 // Same as std::minstd_rand0 but using unsigned not uint_fast32_t.
222 = linear_congruential_engine
<unsigned, 16807UL, 0UL, 2147483647UL>;
225 construct_lcg_at(void* addr
) noexcept
227 return ::new(addr
) lcg_type(bad_seed(addr
));
231 destroy_lcg_at(void* addr
) noexcept
233 static_cast<lcg_type
*>(addr
)->~lcg_type();
237 __lcg(void* ptr
) noexcept
239 auto& lcg
= *static_cast<lcg_type
*>(ptr
);
244 enum Which
: unsigned {
245 device_file
= 1, prng
= 2, rand_s
= 4, getentropy
= 8, arc4random
= 16,
246 rdseed
= 64, rdrand
= 128, darn
= 256,
251 operator|(Which l
, Which r
) noexcept
252 { return Which(unsigned(l
) | unsigned(r
)); }
255 which_source(random_device::result_type (*func
[[maybe_unused
]])(void*),
256 void* file
[[maybe_unused
]])
258 #ifdef _GLIBCXX_USE_CRT_RAND_S
259 if (func
== &__winxp_rand_s
)
265 if (func
== &__x86_rdseed_rdrand
)
268 if (func
== &__x86_rdseed
)
273 if (func
== &__x86_rdrand
)
278 if (func
== &__ppc_darn
)
282 #ifdef _GLIBCXX_USE_DEV_RANDOM
287 #ifdef _GLIBCXX_HAVE_ARC4RANDOM
288 if (func
== __libc_arc4random
)
292 #ifdef _GLIBCXX_HAVE_GETENTROPY
293 if (func
== __libc_getentropy
)
306 return any
; // should be unreachable
311 random_device::_M_init(const std::string
& token
)
314 // If no real random device is supported then use the mt19937 engine.
315 _M_init_pretr1(token
);
323 const char* fname
[[gnu::unused
]] = nullptr;
327 if (token
== "default")
330 fname
= "/dev/urandom";
333 else if (token
== "rdseed")
337 else if (token
== "rdrand" || token
== "rdrnd")
341 else if (token
== "darn")
344 #if defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
345 else if (token
== "hw" || token
== "hardware")
346 which
= rdrand
| rdseed
| darn
;
348 #ifdef _GLIBCXX_USE_CRT_RAND_S
349 else if (token
== "rand_s")
351 #endif // _GLIBCXX_USE_CRT_RAND_S
352 #ifdef _GLIBCXX_HAVE_GETENTROPY
353 else if (token
== "getentropy")
355 #endif // _GLIBCXX_HAVE_GETENTROPY
356 #ifdef _GLIBCXX_HAVE_ARC4RANDOM
357 else if (token
== "arc4random")
359 #endif // _GLIBCXX_HAVE_ARC4RANDOM
360 #ifdef _GLIBCXX_USE_DEV_RANDOM
361 else if (token
== "/dev/urandom" || token
== "/dev/random")
363 fname
= token
.c_str();
366 #endif // _GLIBCXX_USE_DEV_RANDOM
368 else if (token
== "prng")
372 std::__throw_syserr(EINVAL
, __N("random_device::random_device"
373 "(const std::string&):"
374 " unsupported token"));
377 [[maybe_unused
]] const int unsupported
= ENOSYS
;
378 #elif defined ENOTSUP
379 [[maybe_unused
]] const int unsupported
= ENOTSUP
;
381 [[maybe_unused
]] const int unsupported
= 0;
385 #ifdef _GLIBCXX_USE_CRT_RAND_S
388 _M_func
= &__winxp_rand_s
;
391 #endif // _GLIBCXX_USE_CRT_RAND_S
396 unsigned int eax
, ebx
, ecx
, edx
;
397 // Check availability of cpuid and, for now at least, also the
398 // CPU signature for Intel and AMD.
399 if (__get_cpuid_max(0, &ebx
) > 0
400 && (ebx
== signature_INTEL_ebx
|| ebx
== signature_AMD_ebx
))
402 // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18]
403 __cpuid_count(7, 0, eax
, ebx
, ecx
, edx
);
404 if (ebx
& bit_RDSEED
)
407 // CPUID.01H:ECX.RDRAND[bit 30]
408 __cpuid(1, eax
, ebx
, ecx
, edx
);
411 _M_func
= &__x86_rdseed_rdrand
;
415 _M_func
= &__x86_rdseed
;
426 unsigned int eax
, ebx
, ecx
, edx
;
427 // Check availability of cpuid and, for now at least, also the
428 // CPU signature for Intel and AMD.
429 if (__get_cpuid_max(0, &ebx
) > 0
430 && (ebx
== signature_INTEL_ebx
|| ebx
== signature_AMD_ebx
))
432 // CPUID.01H:ECX.RDRAND[bit 30]
433 __cpuid(1, eax
, ebx
, ecx
, edx
);
436 _M_func
= &__x86_rdrand
;
447 if (__builtin_cpu_supports("darn"))
449 _M_func
= &__ppc_darn
;
456 #ifdef _GLIBCXX_HAVE_ARC4RANDOM
457 if (which
& arc4random
)
459 _M_func
= &__libc_arc4random
;
462 #endif // _GLIBCXX_HAVE_ARC4RANDOM
464 #ifdef _GLIBCXX_HAVE_GETENTROPY
465 if (which
& getentropy
)
468 if (::getentropy(&i
, sizeof(i
)) == 0) // On linux the syscall can fail.
470 _M_func
= &__libc_getentropy
;
475 #endif // _GLIBCXX_HAVE_GETENTROPY
477 #ifdef _GLIBCXX_USE_DEV_RANDOM
478 if (which
& device_file
)
480 #ifdef USE_POSIX_FILE_IO
481 _M_fd
= ::open(fname
, O_RDONLY
);
484 // Set _M_file to non-null so that _M_fini() will do clean up.
488 #else // USE_POSIX_FILE_IO
489 _M_file
= static_cast<void*>(std::fopen(fname
, "rb"));
492 #endif // USE_POSIX_FILE_IO
495 #endif // _GLIBCXX_USE_DEV_RANDOM
498 // Either "prng" was requested explicitly, or "default" was requested
499 // but nothing above worked, use a PRNG.
502 static_assert(sizeof(lcg_type
) <= sizeof(_M_fd
), "");
503 static_assert(alignof(lcg_type
) <= alignof(_M_fd
), "");
504 _M_file
= construct_lcg_at(&_M_fd
);
510 auto msg
= __N("random_device::random_device(const std::string&):"
511 " device not available");
513 std::__throw_syserr(err
, msg
);
515 std::__throw_runtime_error(msg
);
516 #endif // USE_MT19937
519 // This function is called by _M_init for targets that use mt19937 for
520 // randomness, and by code compiled against old releases of libstdc++.
522 random_device::_M_init_pretr1(const std::string
& token
)
525 unsigned long seed
= 5489UL;
526 if (token
!= "default" && token
!= "mt19937" && token
!= "prng")
528 const char* nptr
= token
.c_str();
530 seed
= std::strtoul(nptr
, &endptr
, 0);
531 if (*nptr
== '\0' || *endptr
!= '\0')
532 std::__throw_syserr(EINVAL
, __N("random_device::_M_init_pretr1"
533 "(const std::string&)"));
537 // Convert old default token "mt19937" or numeric seed tokens to "default".
538 if (token
== "mt19937" || std::isdigit((unsigned char)token
[0]))
545 // Called by old ABI version of random_device::_M_init(const std::string&).
547 random_device::_M_init(const char* s
, size_t len
)
549 const std::string
token(s
, len
);
551 _M_init_pretr1(token
);
558 random_device::_M_fini()
560 // _M_file == nullptr means no resources to free.
565 if (_M_func
== &__lcg
)
567 destroy_lcg_at(_M_file
);
572 #ifdef _GLIBCXX_USE_DEV_RANDOM
573 #ifdef USE_POSIX_FILE_IO
577 std::fclose(static_cast<FILE*>(_M_file
));
583 random_device::result_type
584 random_device::_M_getval()
591 return _M_func(_M_file
);
595 size_t n
= sizeof(result_type
);
596 #ifdef USE_POSIX_FILE_IO
599 const int e
= ::read(_M_fd
, p
, n
);
603 p
= static_cast<char*>(p
) + e
;
605 else if (e
!= -1 || errno
!= EINTR
)
606 __throw_syserr(errno
, __N("random_device could not be read"));
609 #else // USE_POSIX_FILE_IO
610 const size_t e
= std::fread(p
, n
, 1, static_cast<FILE*>(_M_file
));
612 __throw_runtime_error(__N("random_device could not be read"));
613 #endif // USE_POSIX_FILE_IO
616 #endif // USE_MT19937
619 // Only called by code compiled against old releases of libstdc++.
620 // Forward the call to _M_getval() and let it decide what to do.
621 random_device::result_type
622 random_device::_M_getval_pretr1()
623 { return _M_getval(); }
626 random_device::_M_getentropy() const noexcept
628 const int max
= sizeof(result_type
) * __CHAR_BIT__
;
630 switch(which_source(_M_func
, _M_file
))
649 #if defined _GLIBCXX_USE_DEV_RANDOM \
650 && defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT
652 #ifdef USE_POSIX_FILE_IO
653 const int fd
= _M_fd
;
655 const int fd
= ::fileno(static_cast<FILE*>(_M_file
));
661 if (::ioctl(fd
, RNDGETENTCNT
, &ent
) < 0)
670 return static_cast<double>(ent
);
673 #endif // _GLIBCXX_USE_DEV_RANDOM && _GLIBCXX_HAVE_SYS_IOCTL_H && RNDGETENTCNT
677 template class mersenne_twister_engine
<
683 0xefc60000UL
, 18, 1812433253UL>;
684 #endif // USE_MT19937
688 linear_congruential_engine
<unsigned, 16807UL, 0UL, 2147483647UL>;
689 template struct __detail::_Mod
<unsigned, 2147483647UL, 16807UL, 0UL>;