By hand. I apologize. I made some incremental changes along the way though. There was an off by one error in the retry loop that would have produced a failure fallback if the last cycle of the loop didn’t return all ones for example.
Again, I really apologize and want to withdraw it if I can. Best, Sammy On Tue, Oct 6, 2026, at 6:36 PM, Jonathan Wakely wrote: > > > On Tue, 6 Oct 2026, 21:30 Sammy Al Hashemi, <[email protected]> wrote: >> __ >> Yes I took inspiration from your work :) I hope that it is okay! > > You can't just take somebody else's work and put your name on it. > > Was it copied by hand or produced using an LLM? > > >> Primarily my work here has been a big learning exercise for me. During this >> patch I learned how to properly test with qemu, learned how to properly >> cross-compile, and learned more of the gcc contributing standard and code. I >> should have given you credit in the patch comments I apologize. But once I >> figured out how to properly cross compile here and ensure that this >> workaround was indeed used, I pushed it up for the community to discuss. I >> apologize Jonathan for my lack of foresight here ;(. >> >> Best, >> Sammy >> >> On Tue, Oct 6, 2026, at 4:06 PM, Jonathan Wakely wrote: >>> On Tue, 6 Oct 2026 at 17:35, Sammy Al Hashemi <[email protected]> wrote: >>> > >>> > From: Sammyalhashe <[email protected]> >>> >>> This patch looks remarkably similar to my own patch posted to bugzilla >>> exactly five years ago: >>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100444#c14 >>> >>> Even the wording of the comments is identical. >>> >>> > >>> > Patching libstdc++ random so that it checks if rdrand on amd is broken >>> > before returning a value. >>> > >>> > AMD 3000 CPUs seem to have a bug where the RDRAND instruction always >>> > emits all 1s (aka 4294967295). >>> > >>> > This commit provides a workaround (upon detecting an AMD cpu) - to try >>> > the random function a number of times. If it continues to return the >>> > same broken consistent value, we confirm the random instruction is buggy >>> > on this cpu and emit a runtime error. >>> > >>> > libstdc++-v3/ChangeLog: >>> > >>> > PR libstdc++/100444 >>> > * src/c++11/random.cc (__x86_cpu_sig_ebx): New function. >>> > (__x86_cpu_supports_rdrand, __x86_cpu_supports_rdseed): New >>> > functions. >>> > (__x86_amd_workaround): New function. >>> > (which_source): Look through __x86_amd_workaround to the >>> > wrapped function. >>> > (random_device::_M_init(const string&)): Use new helpers. Wrap >>> > RDRAND and RDSEED with __x86_amd_workaround on AMD CPUs. >>> > (random_device::_M_fini): Do nothing for __x86_amd_workaround. >>> > >>> > Signed-off-by: Sammy Al Hashemi <[email protected]> >>> > --- >>> > I don't have access to an affected Ryzen 3000 system, so this has not >>> > been tested on the hardware that exhibits the bug. >>> > >>> > Tested on x86_64-linux, cross-built and run under `qemu -cpu >>> > EPYC-Rome`. The all-ones failure path was verified with a temporary >>> > fault-injection patch (not included). >>> > >>> > If anyone has an affected machine with a pre-fix BIOS, testing would >>> > be appreciated. >>> > >>> > libstdc++-v3/src/c++11/random.cc | 139 +++++++++++++++++++++++-------- >>> > 1 file changed, 102 insertions(+), 37 deletions(-) >>> > >>> > diff --git a/libstdc++-v3/src/c++11/random.cc >>> > b/libstdc++-v3/src/c++11/random.cc >>> > index 502ba8f44c7..a7888a83c62 100644 >>> > --- a/libstdc++-v3/src/c++11/random.cc >>> > +++ b/libstdc++-v3/src/c++11/random.cc >>> > @@ -146,6 +146,57 @@ namespace std _GLIBCXX_VISIBILITY(default) >>> > #endif >>> > #endif >>> > >>> > +#if USE_RDRAND || USE_RDSEED >>> > + // Check availability of cpuid and if supported, return ebx register. >>> > + // The ebx register can be used to identify the cpu manufacturer. >>> > + inline unsigned int >>> > + __x86_cpu_sig_ebx() noexcept >>> > + { >>> > + unsigned int ebx; >>> > + if (__get_cpuid_max(0, &ebx) > 0) >>> > + return ebx; >>> > + return 0; >>> > + } >>> > + >>> > + inline bool >>> > + __x86_cpu_supports_rdrand() noexcept >>> > + { >>> > +#ifdef USE_RDRAND >>> > + unsigned int eax, ebx, ecx, edx; >>> > + // CPUID.01H:ECX.RDRAND[bit 30] >>> > + __cpuid(1, eax, ebx, ecx, edx); >>> > + return ecx & bit_RDRND; >>> > +#else >>> > + return false; >>> > +#endif >>> > + } >>> > + >>> > + inline bool >>> > + __x86_cpu_supports_rdseed() noexcept >>> > + { >>> > + unsigned int eax, ebx, ecx, edx; >>> > + // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18] >>> > + __cpuid_count(7, 0, eax, ebx, ecx, edx); >>> > + return ebx & bit_RDSEED; >>> > + } >>> > + >>> > + // Workaround AMD Ryzen 3000 bug, see PR libstdc++/100444 >>> > + unsigned int >>> > + __x86_amd_workaround(void* fx) >>> > + { >>> > + auto f = reinterpret_cast<unsigned int(*)(void*)>(fx); >>> > + const unsigned int ALL_ONES = 0xffffffff; >>> > + auto n = f(nullptr); >>> > + int retries = 10; >>> > + while (--retries && n == ALL_ONES) >>> > + n = f(nullptr); >>> > + if (n == ALL_ONES) >>> > + std::__throw_runtime_error(__N("random_device: AMD Ryzen 3000 bug >>> > " >>> > + "detected, BIOS update is >>> > required.")); >>> > + return n; >>> > + } >>> > +#endif >>> > + >>> > #ifdef USE_DARN >>> > unsigned int >>> > __attribute__((target("cpu=power9"))) >>> > @@ -279,6 +330,11 @@ namespace std _GLIBCXX_VISIBILITY(default) >>> > return darn; >>> > #endif >>> > >>> > +#if defined USE_RDRAND || defined USE_RDSEED >>> > + if (func == &__x86_amd_workaround) >>> > + return which_source(reinterpret_cast<decltype(func)>(file), >>> > nullptr); >>> > +#endif >>> > + >>> > #ifdef _GLIBCXX_USE_DEV_RANDOM >>> > if (file != nullptr) >>> > return device_file; >>> > @@ -412,31 +468,33 @@ namespace std _GLIBCXX_VISIBILITY(default) >>> > #ifdef USE_RDSEED >>> > if (which & rdseed) >>> > { >>> > - unsigned int eax, ebx, ecx, edx; >>> > - // Check availability of cpuid and, for now at least, also the >>> > - // CPU signature for Intel, AMD and Hygon. >>> > - if (__get_cpuid_max(0, &ebx) > 0 >>> > - && (ebx == signature_INTEL_ebx >>> > - || ebx == signature_AMD_ebx >>> > - || ebx == signature_HYGON_ebx)) >>> > + const unsigned int sig_ebx = __x86_cpu_sig_ebx(); >>> > + // For now, we only use RDSEED for Intel, AMD, and Hygon >>> > + // processors. >>> > + if (sig_ebx == signature_INTEL_ebx >>> > + || sig_ebx == signature_AMD_ebx >>> > + || sig_ebx == signature_HYGON_ebx) >>> > + { >>> > + if (__x86_cpu_supports_rdseed()) >>> > { >>> > - // CPUID.(EAX=07H, ECX=0H):EBX.RDSEED[bit 18] >>> > - __cpuid_count(7, 0, eax, ebx, ecx, edx); >>> > - if (ebx & bit_RDSEED) >>> > - { >>> > -#ifdef USE_RDRAND >>> > - // CPUID.01H:ECX.RDRAND[bit 30] >>> > - __cpuid(1, eax, ebx, ecx, edx); >>> > - if (ecx & bit_RDRND) >>> > - { >>> > - _M_func = &__x86_rdseed_rdrand; >>> > - return; >>> > - } >>> > -#endif >>> > - _M_func = &__x86_rdseed; >>> > - return; >>> > - } >>> > + if (__x86_cpu_supports_rdrand()) >>> > + { >>> > + _M_func = &__x86_rdseed_rdrand; >>> > + } >>> > + else >>> > + { >>> > + _M_func = &__x86_rdseed; >>> > + } >>> > + >>> > + // AMD 3000 Workaround >>> > + if (sig_ebx == signature_AMD_ebx) >>> > + { >>> > + _M_file = reinterpret_cast<void*>(_M_func); >>> > + _M_func = &__x86_amd_workaround; >>> > + } >>> > + return; >>> > } >>> > + } >>> > err = unsupported; >>> > } >>> > #endif // USE_RDSEED >>> > @@ -444,22 +502,24 @@ namespace std _GLIBCXX_VISIBILITY(default) >>> > #ifdef USE_RDRAND >>> > if (which & rdrand) >>> > { >>> > - unsigned int eax, ebx, ecx, edx; >>> > - // Check availability of cpuid and, for now at least, also the >>> > - // CPU signature for Intel, AMD and Hygon. >>> > - if (__get_cpuid_max(0, &ebx) > 0 >>> > - && (ebx == signature_INTEL_ebx >>> > - || ebx == signature_AMD_ebx >>> > - || ebx == signature_HYGON_ebx)) >>> > + const unsigned int sig_ebx = __x86_cpu_sig_ebx(); >>> > + // For now, we only use RDRAND for Intel, AMD, and Hygon >>> > + // processors. >>> > + if (sig_ebx == signature_INTEL_ebx >>> > + || sig_ebx == signature_AMD_ebx >>> > + || sig_ebx == signature_HYGON_ebx) >>> > + { >>> > + if (__x86_cpu_supports_rdrand()) >>> > { >>> > - // CPUID.01H:ECX.RDRAND[bit 30] >>> > - __cpuid(1, eax, ebx, ecx, edx); >>> > - if (ecx & bit_RDRND) >>> > - { >>> > - _M_func = &__x86_rdrand; >>> > - return; >>> > - } >>> > + _M_func = &__x86_rdrand; >>> > + if (sig_ebx == signature_AMD_ebx) >>> > + { >>> > + _M_file = reinterpret_cast<void*>(_M_func); >>> > + _M_func = &__x86_amd_workaround; >>> > + } >>> > + return; >>> > } >>> > + } >>> > err = unsupported; >>> > } >>> > #endif // USE_RDRAND >>> > @@ -584,6 +644,11 @@ namespace std _GLIBCXX_VISIBILITY(default) >>> > if (!_M_file) >>> > return; >>> > >>> > +#if USE_RDRAND || USE_RDSEED >>> > + if (_M_func == &__x86_amd_workaround) >>> > + return; >>> > +#endif >>> > + >>> > #if USE_LCG >>> > if (_M_func == &__lcg) >>> > { >>> > -- >>> > 2.55.0 >>> > >>> >>>
