Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(165982)

Side by Side Diff: Python/random.c

Issue 18756: os.urandom() fails under high load
Patch Set: Created 5 years, 11 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Python/pythonrun.c ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #include "Python.h" 1 #include "Python.h"
2 #ifdef MS_WINDOWS 2 #ifdef MS_WINDOWS
3 #include <windows.h> 3 #include <windows.h>
4 #else 4 #else
5 #include <fcntl.h> 5 #include <fcntl.h>
6 #endif 6 #endif
7 7
8 #ifdef Py_DEBUG 8 #ifdef Py_DEBUG
9 int _Py_HashSecret_Initialized = 0; 9 int _Py_HashSecret_Initialized = 0;
10 #else 10 #else
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 "secret using RAND_pseudo_bytes"); 83 "secret using RAND_pseudo_bytes");
84 } 84 }
85 return -1; 85 return -1;
86 } 86 }
87 return 0; 87 return 0;
88 } 88 }
89 #endif /* __VMS */ 89 #endif /* __VMS */
90 90
91 91
92 #if !defined(MS_WINDOWS) && !defined(__VMS) 92 #if !defined(MS_WINDOWS) && !defined(__VMS)
93 static int urandom_fd = -1;
93 94
94 /* Read size bytes from /dev/urandom into buffer. 95 /* Read size bytes from /dev/urandom into buffer.
95 Call Py_FatalError() on error. */ 96 Call Py_FatalError() on error. */
96 static void 97 static void
97 dev_urandom_noraise(char *buffer, Py_ssize_t size) 98 dev_urandom_noraise(char *buffer, Py_ssize_t size)
98 { 99 {
99 int fd; 100 int fd;
100 Py_ssize_t n; 101 Py_ssize_t n;
101 102
102 assert (0 < size); 103 assert (0 < size);
(...skipping 23 matching lines...) Expand all
126 Return 0 on success, raise an exception and return -1 on error. */ 127 Return 0 on success, raise an exception and return -1 on error. */
127 static int 128 static int
128 dev_urandom_python(char *buffer, Py_ssize_t size) 129 dev_urandom_python(char *buffer, Py_ssize_t size)
129 { 130 {
130 int fd; 131 int fd;
131 Py_ssize_t n; 132 Py_ssize_t n;
132 133
133 if (size <= 0) 134 if (size <= 0)
134 return 0; 135 return 0;
135 136
136 Py_BEGIN_ALLOW_THREADS 137 if (urandom_fd >= 0)
137 fd = open("/dev/urandom", O_RDONLY); 138 fd = urandom_fd;
138 Py_END_ALLOW_THREADS 139 else {
139 if (fd < 0) 140 Py_BEGIN_ALLOW_THREADS
140 { 141 fd = open("/dev/urandom", O_RDONLY);
christian.heimes 2013/08/16 21:48:43 You should add O_CLOEXEC here or ...
141 if (errno == ENOENT || errno == ENXIO || 142 Py_END_ALLOW_THREADS
142 errno == ENODEV || errno == EACCES) 143 if (fd < 0)
143 PyErr_SetString(PyExc_NotImplementedError, 144 {
144 "/dev/urandom (or equivalent) not found"); 145 if (errno == ENOENT || errno == ENXIO ||
146 errno == ENODEV || errno == EACCES)
147 PyErr_SetString(PyExc_NotImplementedError,
148 "/dev/urandom (or equivalent) not found");
149 else
150 PyErr_SetFromErrno(PyExc_OSError);
151 return -1;
152 }
153 if (urandom_fd >= 0) {
154 /* urandom_fd was initialized by another thread while we were
155 not holding the GIL, keep it. */
156 close(fd);
157 fd = urandom_fd;
158 }
145 else 159 else
146 PyErr_SetFromErrno(PyExc_OSError); 160 urandom_fd = fd;
christian.heimes 2013/08/16 21:48:43 ... set FD_CLOEXEC here.
AntoinePitrou 2013/08/16 21:57:35 I'm not sure it's in the scope for this patch. I c
147 return -1;
148 } 161 }
149 162
150 Py_BEGIN_ALLOW_THREADS 163 Py_BEGIN_ALLOW_THREADS
151 do { 164 do {
152 do { 165 do {
153 n = read(fd, buffer, (size_t)size); 166 n = read(fd, buffer, (size_t)size);
154 } while (n < 0 && errno == EINTR); 167 } while (n < 0 && errno == EINTR);
155 if (n <= 0) 168 if (n <= 0)
156 break; 169 break;
157 buffer += n; 170 buffer += n;
158 size -= (Py_ssize_t)n; 171 size -= (Py_ssize_t)n;
159 } while (0 < size); 172 } while (0 < size);
160 Py_END_ALLOW_THREADS 173 Py_END_ALLOW_THREADS
161 174
162 if (n <= 0) 175 if (n <= 0)
163 { 176 {
164 /* stop on error or if read(size) returned 0 */ 177 /* stop on error or if read(size) returned 0 */
christian.heimes 2013/08/16 21:48:43 I suggest that you close and invalidate urandom_fd
AntoinePitrou 2013/08/16 21:57:35 Good point.
165 if (n < 0) 178 if (n < 0)
166 PyErr_SetFromErrno(PyExc_OSError); 179 PyErr_SetFromErrno(PyExc_OSError);
167 else 180 else
168 PyErr_Format(PyExc_RuntimeError, 181 PyErr_Format(PyExc_RuntimeError,
169 "Failed to read %zi bytes from /dev/urandom", 182 "Failed to read %zi bytes from /dev/urandom",
170 size); 183 size);
171 close(fd);
172 return -1; 184 return -1;
173 } 185 }
174 close(fd);
175 return 0; 186 return 0;
176 } 187 }
188
189 static void
190 dev_urandom_close(void)
191 {
192 if (urandom_fd >= 0) {
193 close(urandom_fd);
194 urandom_fd = -1;
195 }
196 }
197
177 #endif /* !defined(MS_WINDOWS) && !defined(__VMS) */ 198 #endif /* !defined(MS_WINDOWS) && !defined(__VMS) */
178 199
179 /* Fill buffer with pseudo-random bytes generated by a linear congruent 200 /* Fill buffer with pseudo-random bytes generated by a linear congruent
180 generator (LCG): 201 generator (LCG):
181 202
182 x(n+1) = (x(n) * 214013 + 2531011) % 2^32 203 x(n+1) = (x(n) * 214013 + 2531011) % 2^32
183 204
184 Use bits 23..16 of x(n) to generate a byte. */ 205 Use bits 23..16 of x(n) to generate a byte. */
185 static void 206 static void
186 lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size) 207 lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 (void)win32_urandom((unsigned char *)secret, secret_size, 0); 285 (void)win32_urandom((unsigned char *)secret, secret_size, 0);
265 #else /* #ifdef MS_WINDOWS */ 286 #else /* #ifdef MS_WINDOWS */
266 # ifdef __VMS 287 # ifdef __VMS
267 vms_urandom((unsigned char *)secret, secret_size, 0); 288 vms_urandom((unsigned char *)secret, secret_size, 0);
268 # else 289 # else
269 dev_urandom_noraise((char*)secret, secret_size); 290 dev_urandom_noraise((char*)secret, secret_size);
270 # endif 291 # endif
271 #endif 292 #endif
272 } 293 }
273 } 294 }
295
296 void
297 _PyRandom_Fini(void)
298 {
299 #if !defined(MS_WINDOWS) && !defined(__VMS)
300 dev_urandom_close();
301 #endif
302 }
OLDNEW
« no previous file with comments | « Python/pythonrun.c ('k') | no next file » | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+