/Users/buildslave/jenkins/workspace/coverage/llvm-project/libcxx/src/random.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===----------------------------------------------------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include <__config> |
10 | | |
11 | | #if defined(_LIBCPP_USING_WIN32_RANDOM) |
12 | | // Must be defined before including stdlib.h to enable rand_s(). |
13 | | # define _CRT_RAND_S |
14 | | #endif // defined(_LIBCPP_USING_WIN32_RANDOM) |
15 | | |
16 | | #include <limits> |
17 | | #include <random> |
18 | | #include <system_error> |
19 | | |
20 | | #if defined(__sun__) |
21 | | # define rename solaris_headers_are_broken |
22 | | #endif // defined(__sun__) |
23 | | |
24 | | #include <errno.h> |
25 | | #include <stdio.h> |
26 | | #include <stdlib.h> |
27 | | |
28 | | #if defined(_LIBCPP_USING_GETENTROPY) |
29 | | # include <sys/random.h> |
30 | | #elif defined(_LIBCPP_USING_DEV_RANDOM) |
31 | | # include <fcntl.h> |
32 | | # include <unistd.h> |
33 | | # if __has_include(<sys/ioctl.h>) && __has_include(<linux/random.h>) |
34 | | # include <sys/ioctl.h> |
35 | | # include <linux/random.h> |
36 | | # endif |
37 | | #elif defined(_LIBCPP_USING_NACL_RANDOM) |
38 | | # include <nacl/nacl_random.h> |
39 | | #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG) |
40 | | # include <zircon/syscalls.h> |
41 | | #endif |
42 | | |
43 | | |
44 | | _LIBCPP_BEGIN_NAMESPACE_STD |
45 | | |
46 | | #if defined(_LIBCPP_USING_GETENTROPY) |
47 | | |
48 | | random_device::random_device(const string& __token) |
49 | | { |
50 | | if (__token != "/dev/urandom") |
51 | | __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); |
52 | | } |
53 | | |
54 | | random_device::~random_device() |
55 | | { |
56 | | } |
57 | | |
58 | | unsigned |
59 | | random_device::operator()() |
60 | | { |
61 | | unsigned r; |
62 | | size_t n = sizeof(r); |
63 | | int err = getentropy(&r, n); |
64 | | if (err) |
65 | | __throw_system_error(errno, "random_device getentropy failed"); |
66 | | return r; |
67 | | } |
68 | | |
69 | | #elif defined(_LIBCPP_USING_ARC4_RANDOM) |
70 | | |
71 | | random_device::random_device(const string&) |
72 | 0 | { |
73 | 0 | } |
74 | | |
75 | | random_device::~random_device() |
76 | 0 | { |
77 | 0 | } |
78 | | |
79 | | unsigned |
80 | | random_device::operator()() |
81 | 0 | { |
82 | 0 | return arc4random(); |
83 | 0 | } |
84 | | |
85 | | #elif defined(_LIBCPP_USING_DEV_RANDOM) |
86 | | |
87 | | random_device::random_device(const string& __token) |
88 | | : __f_(open(__token.c_str(), O_RDONLY)) |
89 | | { |
90 | | if (__f_ < 0) |
91 | | __throw_system_error(errno, ("random_device failed to open " + __token).c_str()); |
92 | | } |
93 | | |
94 | | random_device::~random_device() |
95 | | { |
96 | | close(__f_); |
97 | | } |
98 | | |
99 | | unsigned |
100 | | random_device::operator()() |
101 | | { |
102 | | unsigned r; |
103 | | size_t n = sizeof(r); |
104 | | char* p = reinterpret_cast<char*>(&r); |
105 | | while (n > 0) |
106 | | { |
107 | | ssize_t s = read(__f_, p, n); |
108 | | if (s == 0) |
109 | | __throw_system_error(ENODATA, "random_device got EOF"); |
110 | | if (s == -1) |
111 | | { |
112 | | if (errno != EINTR) |
113 | | __throw_system_error(errno, "random_device got an unexpected error"); |
114 | | continue; |
115 | | } |
116 | | n -= static_cast<size_t>(s); |
117 | | p += static_cast<size_t>(s); |
118 | | } |
119 | | return r; |
120 | | } |
121 | | |
122 | | #elif defined(_LIBCPP_USING_NACL_RANDOM) |
123 | | |
124 | | random_device::random_device(const string& __token) |
125 | | { |
126 | | if (__token != "/dev/urandom") |
127 | | __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); |
128 | | int error = nacl_secure_random_init(); |
129 | | if (error) |
130 | | __throw_system_error(error, ("random device failed to open " + __token).c_str()); |
131 | | } |
132 | | |
133 | | random_device::~random_device() |
134 | | { |
135 | | } |
136 | | |
137 | | unsigned |
138 | | random_device::operator()() |
139 | | { |
140 | | unsigned r; |
141 | | size_t n = sizeof(r); |
142 | | size_t bytes_written; |
143 | | int error = nacl_secure_random(&r, n, &bytes_written); |
144 | | if (error != 0) |
145 | | __throw_system_error(error, "random_device failed getting bytes"); |
146 | | else if (bytes_written != n) |
147 | | __throw_runtime_error("random_device failed to obtain enough bytes"); |
148 | | return r; |
149 | | } |
150 | | |
151 | | #elif defined(_LIBCPP_USING_WIN32_RANDOM) |
152 | | |
153 | | random_device::random_device(const string& __token) |
154 | | { |
155 | | if (__token != "/dev/urandom") |
156 | | __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); |
157 | | } |
158 | | |
159 | | random_device::~random_device() |
160 | | { |
161 | | } |
162 | | |
163 | | unsigned |
164 | | random_device::operator()() |
165 | | { |
166 | | unsigned r; |
167 | | errno_t err = rand_s(&r); |
168 | | if (err) |
169 | | __throw_system_error(err, "random_device rand_s failed."); |
170 | | return r; |
171 | | } |
172 | | |
173 | | #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG) |
174 | | |
175 | | random_device::random_device(const string& __token) { |
176 | | if (__token != "/dev/urandom") |
177 | | __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); |
178 | | } |
179 | | |
180 | | random_device::~random_device() {} |
181 | | |
182 | | unsigned random_device::operator()() { |
183 | | // Implicitly link against the vDSO system call ABI without |
184 | | // requiring the final link to specify -lzircon explicitly when |
185 | | // statically linking libc++. |
186 | | # pragma comment(lib, "zircon") |
187 | | |
188 | | // The system call cannot fail. It returns only when the bits are ready. |
189 | | unsigned r; |
190 | | _zx_cprng_draw(&r, sizeof(r)); |
191 | | return r; |
192 | | } |
193 | | |
194 | | #else |
195 | | #error "Random device not implemented for this architecture" |
196 | | #endif |
197 | | |
198 | | double |
199 | | random_device::entropy() const noexcept |
200 | 0 | { |
201 | | #if defined(_LIBCPP_USING_DEV_RANDOM) && defined(RNDGETENTCNT) |
202 | | int ent; |
203 | | if (::ioctl(__f_, RNDGETENTCNT, &ent) < 0) |
204 | | return 0; |
205 | | |
206 | | if (ent < 0) |
207 | | return 0; |
208 | | |
209 | | if (ent > std::numeric_limits<result_type>::digits) |
210 | | return std::numeric_limits<result_type>::digits; |
211 | | |
212 | | return ent; |
213 | | #elif defined(_LIBCPP_USING_ARC4_RANDOM) || defined(_LIBCPP_USING_FUCHSIA_CPRNG) |
214 | | return std::numeric_limits<result_type>::digits; |
215 | | #else |
216 | | return 0; |
217 | | #endif |
218 | 0 | } |
219 | | |
220 | | _LIBCPP_END_NAMESPACE_STD |