Make std::random_device retry after short reads
authorJonathan Wakely <jwakely@redhat.com>
Thu, 17 Sep 2015 15:06:42 +0000 (16:06 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Thu, 17 Sep 2015 15:06:42 +0000 (16:06 +0100)
PR libstdc++/65142
* src/c++11/random.cc (random_device::_M_getval()): Retry after short
reads.

From-SVN: r227872

libstdc++-v3/ChangeLog
libstdc++-v3/src/c++11/random.cc

index c70ad43..25aa16b 100644 (file)
@@ -1,5 +1,9 @@
 2015-09-17  Jonathan Wakely  <jwakely@redhat.com>
 
+       PR libstdc++/65142
+       * src/c++11/random.cc (random_device::_M_getval()): Retry after short
+       reads.
+
        * include/std/system_error (error_code::operator bool(),
        error_condition::operator bool()): Remove redundant conditional
        expression.
index 1d102c7..f1d6125 100644 (file)
@@ -130,16 +130,26 @@ namespace std _GLIBCXX_VISIBILITY(default)
 #endif
 
     result_type __ret;
-
+    void* p = &__ret;
+    size_t n = sizeof(result_type);
 #ifdef _GLIBCXX_HAVE_UNISTD_H
-    auto e = read(fileno(static_cast<FILE*>(_M_file)),
-                 static_cast<void*>(&__ret), sizeof(result_type));
+    do
+      {
+       const int e = read(fileno(static_cast<FILE*>(_M_file)), p, n);
+       if (e > 0)
+         {
+           n -= e;
+           p = static_cast<char*>(p) + e;
+         }
+       else if (e != -1 || errno != EINTR)
+         __throw_runtime_error(__N("random_device could not be read"));
+      }
+    while (n > 0);
 #else
-    auto e = std::fread(static_cast<void*>(&__ret), sizeof(result_type),
-                       1, static_cast<FILE*>(_M_file));
+    const size_t e = std::fread(p, n, 1, static_cast<FILE*>(_M_file));
+    if (e != 1)
+      __throw_runtime_error(__N("random_device could not be read"));
 #endif
-    if (e != sizeof(result_type))
-      __throw_runtime_error(__N("random_device could not read enough bytes"));
 
     return __ret;
   }