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
>>> >
>>> 
>>> 

Reply via email to