3 // Copyright (C) 2012-2021 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
30 #ifdef _GLIBCXX_USE_C99_STDINT_TR1
32 #if defined __i386__ || defined __x86_64__
34 # ifdef _GLIBCXX_X86_RDRAND
37 # ifdef _GLIBCXX_X86_RDSEED
40 #elif defined __powerpc__ && defined __BUILTIN_CPU_SUPPORTS__
46 #include <cctype> // For std::isdigit.
48 #if defined _GLIBCXX_HAVE_UNISTD_H && defined _GLIBCXX_HAVE_FCNTL_H
51 // Use POSIX open, close, read etc. instead of ISO fopen, fclose, fread
52 # define USE_POSIX_FILE_IO
55 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H
56 # include <sys/ioctl.h>
59 #ifdef _GLIBCXX_HAVE_LINUX_TYPES_H
60 # include <linux/types.h>
63 #ifdef _GLIBCXX_HAVE_LINUX_RANDOM_H
64 # include <linux/random.h>
67 #ifdef _GLIBCXX_USE_CRT_RAND_S
71 #if defined _GLIBCXX_USE_CRT_RAND_S || defined _GLIBCXX_USE_DEV_RANDOM
72 // The OS provides a source of randomness we can use.
73 # pragma GCC poison _M_mt
74 #elif defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
75 // Hardware instructions might be available, but use cpuid checks at runtime.
76 # pragma GCC poison _M_mt
77 // If the runtime cpuid checks fail we'll use a linear congruential engine.
80 // Use the mt19937 member of the union, as in previous GCC releases.
81 # define USE_MT19937 1
88 namespace std
_GLIBCXX_VISIBILITY(default)
94 __attribute__ ((target("rdrnd")))
97 unsigned int retries
= 100;
100 while (__builtin_ia32_rdrand32_step(&val
) == 0)
102 std::__throw_runtime_error(__N("random_device: rdrand failed"));
110 __attribute__ ((target("rdseed")))
111 __x86_rdseed(void* fallback
)
113 unsigned int retries
= 100;
116 while (__builtin_ia32_rdseed_si_step(&val
) == 0)
120 if (auto f
= reinterpret_cast<unsigned int(*)(void*)>(fallback
))
122 std::__throw_runtime_error(__N("random_device: rdseed failed"));
124 __builtin_ia32_pause();
132 __attribute__ ((target("rdseed,rdrnd")))
133 __x86_rdseed_rdrand(void*)
135 return __x86_rdseed(reinterpret_cast<void*>(&__x86_rdrand
));
142 __attribute__((target("cpu=power9")))
145 const uint64_t failed
= -1;
146 unsigned int retries
= 10;
147 uint64_t val
= __builtin_darn();
148 while (val
== failed
) [[__unlikely__
]]
151 std::__throw_runtime_error(__N("random_device: darn failed"));
152 val
= __builtin_darn();
154 return (uint32_t)val
;
158 #ifdef _GLIBCXX_USE_CRT_RAND_S
160 __winxp_rand_s(void*)
163 if (::rand_s(&val
) != 0)
164 std::__throw_runtime_error(__N("random_device: rand_s failed"));
170 // TODO: use this to seed std::mt19937 engine too.
172 bad_seed(void* p
) noexcept
174 // Poor quality seed based on hash of the current time and the address
175 // of the object being seeded. Better than using the same default seed
176 // for every object though.
177 const uint64_t bits
[] = {
178 (uint64_t) chrono::system_clock::now().time_since_epoch().count(),
179 (uint64_t) reinterpret_cast<uintptr_t>(p
)
181 auto bytes
= reinterpret_cast<const unsigned char*>(bits
);
182 // 32-bit FNV-1a hash
183 uint32_t h
= 2166136261u;
184 for (unsigned i
= 0; i
< sizeof(bits
); ++i
)
192 // Same as std::minstd_rand0 but using unsigned not uint_fast32_t.
194 = linear_congruential_engine
<unsigned, 16807UL, 0UL, 2147483647UL>;
197 construct_lcg_at(void* addr
) noexcept
199 return ::new(addr
) lcg_type(bad_seed(addr
));
203 destroy_lcg_at(void* addr
) noexcept
205 static_cast<lcg_type
*>(addr
)->~lcg_type();
209 __lcg(void* ptr
) noexcept
211 auto& lcg
= *static_cast<lcg_type
*>(ptr
);
216 enum Which
: unsigned {
217 device_file
= 1, prng
= 2, rand_s
= 4,
218 rdseed
= 64, rdrand
= 128, darn
= 256,
223 operator|(Which l
, Which r
) noexcept
224 { return Which(unsigned(l
) | unsigned(r
)); }
227 which_source(random_device::result_type (*func
[[maybe_unused
]])(void*),
228 void* file
[[maybe_unused
]])
230 #ifdef _GLIBCXX_USE_CRT_RAND_S
231 if (func
== &__winxp_rand_s
)
237 if (func
== &__x86_rdseed_rdrand
)
240 if (func
== &__x86_rdseed
)
245 if (func
== &__x86_rdrand
)
250 if (func
== &__ppc_darn
)
254 #ifdef _GLIBCXX_USE_DEV_RANDOM
268 return any
; // should be unreachable
273 random_device::_M_init(const std::string
& token
)
276 // If no real random device is supported then use the mt19937 engine.
277 _M_init_pretr1(token
);
285 const char* fname
[[gnu::unused
]] = nullptr;
289 if (token
== "default")
292 fname
= "/dev/urandom";
295 else if (token
== "rdseed")
299 else if (token
== "rdrand" || token
== "rdrnd")
303 else if (token
== "darn")
306 #if defined USE_RDRAND || defined USE_RDSEED || defined USE_DARN
307 else if (token
== "hw" || token
== "hardware")
308 which
= rdrand
| rdseed
| darn
;
310 #ifdef _GLIBCXX_USE_CRT_RAND_S
311 else if (token
== "rand_s")
313 #endif // _GLIBCXX_USE_CRT_RAND_S
314 #ifdef _GLIBCXX_USE_DEV_RANDOM
315 else if (token
== "/dev/urandom" || token
== "/dev/random")
317 fname
= token
.c_str();
320 #endif // _GLIBCXX_USE_DEV_RANDOM
322 else if (token
== "prng")
326 std::__throw_runtime_error(
327 __N("random_device::random_device(const std::string&):"
328 " unsupported token"));
330 #ifdef _GLIBCXX_USE_CRT_RAND_S
333 _M_func
= &__winxp_rand_s
;
336 #endif // _GLIBCXX_USE_CRT_RAND_S
341 unsigned int eax
, ebx
, ecx
, edx
;
342 // Check availability of cpuid and, for now at least, also the
343 // CPU signature for Intel and AMD.
344 if (__get_cpuid_max(0, &ebx
) > 0
345 && (ebx
== signature_INTEL_ebx
|| ebx
== signature_AMD_ebx
))
347 // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18]
348 __cpuid_count(7, 0, eax
, ebx
, ecx
, edx
);
349 if (ebx
& bit_RDSEED
)
352 // CPUID.01H:ECX.RDRAND[bit 30]
353 __cpuid(1, eax
, ebx
, ecx
, edx
);
356 _M_func
= &__x86_rdseed_rdrand
;
360 _M_func
= &__x86_rdseed
;
370 unsigned int eax
, ebx
, ecx
, edx
;
371 // Check availability of cpuid and, for now at least, also the
372 // CPU signature for Intel and AMD.
373 if (__get_cpuid_max(0, &ebx
) > 0
374 && (ebx
== signature_INTEL_ebx
|| ebx
== signature_AMD_ebx
))
376 // CPUID.01H:ECX.RDRAND[bit 30]
377 __cpuid(1, eax
, ebx
, ecx
, edx
);
380 _M_func
= &__x86_rdrand
;
390 if (__builtin_cpu_supports("darn"))
392 _M_func
= &__ppc_darn
;
398 #ifdef _GLIBCXX_USE_DEV_RANDOM
399 if (which
& device_file
)
401 #ifdef USE_POSIX_FILE_IO
402 _M_fd
= ::open(fname
, O_RDONLY
);
405 // Set _M_file to non-null so that _M_fini() will do clean up.
409 #else // USE_POSIX_FILE_IO
410 _M_file
= static_cast<void*>(std::fopen(fname
, "rb"));
413 #endif // USE_POSIX_FILE_IO
415 #endif // _GLIBCXX_USE_DEV_RANDOM
418 // Either "prng" was requested explicitly, or "default" was requested
419 // but nothing above worked, use a PRNG.
422 static_assert(sizeof(lcg_type
) <= sizeof(_M_fd
), "");
423 static_assert(alignof(lcg_type
) <= alignof(_M_fd
), "");
424 _M_file
= construct_lcg_at(&_M_fd
);
430 std::__throw_runtime_error(
431 __N("random_device::random_device(const std::string&):"
432 " device not available"));
433 #endif // USE_MT19937
436 // This function is called by _M_init for targets that use mt19937 for
437 // randomness, and by code compiled against old releases of libstdc++.
439 random_device::_M_init_pretr1(const std::string
& token
)
442 unsigned long seed
= 5489UL;
443 if (token
!= "default" && token
!= "mt19937" && token
!= "prng")
445 const char* nptr
= token
.c_str();
447 seed
= std::strtoul(nptr
, &endptr
, 0);
448 if (*nptr
== '\0' || *endptr
!= '\0')
449 std::__throw_runtime_error(__N("random_device::_M_init_pretr1"
450 "(const std::string&)"));
454 // Convert old default token "mt19937" or numeric seed tokens to "default".
455 if (token
== "mt19937" || std::isdigit((unsigned char)token
[0]))
462 // Called by old ABI version of random_device::_M_init(const std::string&).
464 random_device::_M_init(const char* s
, size_t len
)
466 const std::string
token(s
, len
);
468 _M_init_pretr1(token
);
475 random_device::_M_fini()
477 // _M_file == nullptr means no resources to free.
482 if (_M_func
== &__lcg
)
484 destroy_lcg_at(_M_file
);
489 #ifdef USE_POSIX_FILE_IO
493 std::fclose(static_cast<FILE*>(_M_file
));
498 random_device::result_type
499 random_device::_M_getval()
506 return _M_func(_M_file
);
510 size_t n
= sizeof(result_type
);
511 #ifdef USE_POSIX_FILE_IO
514 const int e
= ::read(_M_fd
, p
, n
);
518 p
= static_cast<char*>(p
) + e
;
520 else if (e
!= -1 || errno
!= EINTR
)
521 __throw_runtime_error(__N("random_device could not be read"));
524 #else // USE_POSIX_FILE_IO
525 const size_t e
= std::fread(p
, n
, 1, static_cast<FILE*>(_M_file
));
527 __throw_runtime_error(__N("random_device could not be read"));
528 #endif // USE_POSIX_FILE_IO
531 #endif // USE_MT19937
534 // Only called by code compiled against old releases of libstdc++.
535 // Forward the call to _M_getval() and let it decide what to do.
536 random_device::result_type
537 random_device::_M_getval_pretr1()
538 { return _M_getval(); }
541 random_device::_M_getentropy() const noexcept
543 const int max
= sizeof(result_type
) * __CHAR_BIT__
;
545 switch(which_source(_M_func
, _M_file
))
561 #if defined _GLIBCXX_USE_DEV_RANDOM \
562 && defined _GLIBCXX_HAVE_SYS_IOCTL_H && defined RNDGETENTCNT
564 #ifdef USE_POSIX_FILE_IO
565 const int fd
= _M_fd
;
567 const int fd
= ::fileno(static_cast<FILE*>(_M_file
));
573 if (::ioctl(fd
, RNDGETENTCNT
, &ent
) < 0)
582 return static_cast<double>(ent
);
585 #endif // _GLIBCXX_USE_DEV_RANDOM && _GLIBCXX_HAVE_SYS_IOCTL_H && RNDGETENTCNT
589 template class mersenne_twister_engine
<
595 0xefc60000UL
, 18, 1812433253UL>;
596 #endif // USE_MT19937
600 linear_congruential_engine
<unsigned, 16807UL, 0UL, 2147483647UL>;
601 template struct __detail::_Mod
<unsigned, 2147483647UL, 16807UL, 0UL>;
604 #endif // _GLIBCXX_USE_C99_STDINT_TR1