diff options
author | David Majnemer <david.majnemer@gmail.com> | 2014-06-03 02:40:39 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2014-06-03 02:40:39 +0000 |
commit | 2dfdfdf45c4c26a628527a542d9c4deaaf300ea1 (patch) | |
tree | 5cc56dac5fafb9497f378e6af6f8a90318c3ac0e /libcxx/src | |
parent | 1e9592a9c71ed87c806946ad2cccc1bcb472324d (diff) | |
download | bcm5719-llvm-2dfdfdf45c4c26a628527a542d9c4deaaf300ea1.tar.gz bcm5719-llvm-2dfdfdf45c4c26a628527a542d9c4deaaf300ea1.zip |
[libc++] Don't return uninitialized data from random_device::operator()
Make sure we appropriately retry calls to read if the return result is
less than what we asked for.
Additionally, check and handle IO errors: EINTR results in the read
operation getting restarted; other errors turn into exceptions.
llvm-svn: 210061
Diffstat (limited to 'libcxx/src')
-rw-r--r-- | libcxx/src/random.cpp | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/libcxx/src/random.cpp b/libcxx/src/random.cpp index 21e21689a87..86017ef0d46 100644 --- a/libcxx/src/random.cpp +++ b/libcxx/src/random.cpp @@ -62,7 +62,22 @@ unsigned random_device::operator()() { unsigned r; - read(__f_, &r, sizeof(r)); + size_t n = sizeof(r); + char* p = reinterpret_cast<char*>(&r); + while (n > 0) + { + ssize_t s = read(__f_, p, n); + if (s == 0) + __throw_system_error(ENODATA, "random_device got EOF"); + if (s == -1) + { + if (errno != EINTR) + __throw_system_error(errno, "random_device got an unexpected error"); + continue; + } + n -= static_cast<size_t>(s); + p += static_cast<size_t>(s); + } return r; } #endif // defined(_WIN32) |