[Bug target/94087] std::random_device often fails when used from multiple threads

redi at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Thu May 14 12:01:31 GMT 2020


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087

--- Comment #21 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to rguenther@suse.de from comment #18)
> Note in virtualized environments support for RDRAND might be disabled
> while RDSEED is enabled(?) even if no such hardware configuration
> exists [by now].  If I were a chip manufacturer (hello VIA?) that
> at the moment neither implements RDRAND nor RDSEED a good option
> would be to only go for the stronger RDSEED and leave RDRAND 
> unimplemented.

So we'd want something like this to check if RDRAND is usable:

--- a/libstdc++-v3/src/c++11/random.cc
+++ b/libstdc++-v3/src/c++11/random.cc
@@ -97,7 +97,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
 #if USE_RDSEED
     unsigned int
     __attribute__ ((target("rdseed")))
-    __x86_rdseed(void*)
+    __x86_rdseed(void* fallback)
     {
       unsigned int retries = 100;
       unsigned int val;
@@ -105,12 +105,25 @@ namespace std _GLIBCXX_VISIBILITY(default)
       while (__builtin_ia32_rdseed_si_step(&val) == 0)
        {
          if (--retries == 0)
-           std::__throw_runtime_error(__N("random_device: rdseed failed"));
+           {
+             if (auto f = reinterpret_cast<unsigned int(*)(void*)>(fallback))
+               return f(nullptr);
+             std::__throw_runtime_error(__N("random_device: rdseed failed"));
+           }
          __builtin_ia32_pause();
        }

       return val;
     }
+
+#if USE_RDRAND
+    unsigned int
+    __attribute__ ((target("rdseed,rdrnd")))
+    __x86_rdseed_rdrand(void*)
+    {
+      return __x86_rdseed(reinterpret_cast<void*>(&__x86_rdrand));
+    }
+#endif
 #endif

 #ifdef _GLIBCXX_USE_CRT_RAND_S
@@ -205,6 +218,15 @@ namespace std _GLIBCXX_VISIBILITY(default)
            __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;
              }


More information about the Gcc-bugs mailing list