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

Side by Side Diff: Python/random.c

Issue 18756: os.urandom() fails under high load
Patch Set: Created 6 years, 2 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);
141 PyErr_SetString(PyExc_NotImplementedError, 142 Py_END_ALLOW_THREADS
142 "/dev/urandom (or equivalent) not found"); 143 if (fd < 0)
143 return -1; 144 {
145 PyErr_SetString(PyExc_NotImplementedError,
146 "/dev/urandom (or equivalent) not found");
147 return -1;
148 }
149 if (urandom_fd >= 0) {
150 /* urandom_fd was initialized by another thread while we were
151 not holding the GIL, keep it. */
152 close(fd);
153 fd = urandom_fd;
154 }
155 else
156 urandom_fd = fd;
144 } 157 }
145 158
146 Py_BEGIN_ALLOW_THREADS 159 Py_BEGIN_ALLOW_THREADS
147 do { 160 do {
148 do { 161 do {
149 n = read(fd, buffer, (size_t)size); 162 n = read(fd, buffer, (size_t)size);
150 } while (n < 0 && errno == EINTR); 163 } while (n < 0 && errno == EINTR);
151 if (n <= 0) 164 if (n <= 0)
152 break; 165 break;
153 buffer += n; 166 buffer += n;
154 size -= (Py_ssize_t)n; 167 size -= (Py_ssize_t)n;
155 } while (0 < size); 168 } while (0 < size);
156 Py_END_ALLOW_THREADS 169 Py_END_ALLOW_THREADS
157 170
158 if (n <= 0) 171 if (n <= 0)
159 { 172 {
160 /* stop on error or if read(size) returned 0 */ 173 /* stop on error or if read(size) returned 0 */
161 if (n < 0) 174 if (n < 0)
162 PyErr_SetFromErrno(PyExc_OSError); 175 PyErr_SetFromErrno(PyExc_OSError);
163 else 176 else
164 PyErr_Format(PyExc_RuntimeError, 177 PyErr_Format(PyExc_RuntimeError,
165 "Failed to read %zi bytes from /dev/urandom", 178 "Failed to read %zi bytes from /dev/urandom",
166 size); 179 size);
167 close(fd);
168 return -1; 180 return -1;
169 } 181 }
170 close(fd);
171 return 0; 182 return 0;
172 } 183 }
184
185 static void
186 dev_urandom_close(void)
187 {
188 if (urandom_fd >= 0) {
189 close(urandom_fd);
190 urandom_fd = -1;
191 }
192 }
193
173 #endif /* !defined(MS_WINDOWS) && !defined(__VMS) */ 194 #endif /* !defined(MS_WINDOWS) && !defined(__VMS) */
174 195
175 /* Fill buffer with pseudo-random bytes generated by a linear congruent 196 /* Fill buffer with pseudo-random bytes generated by a linear congruent
176 generator (LCG): 197 generator (LCG):
177 198
178 x(n+1) = (x(n) * 214013 + 2531011) % 2^32 199 x(n+1) = (x(n) * 214013 + 2531011) % 2^32
179 200
180 Use bits 23..16 of x(n) to generate a byte. */ 201 Use bits 23..16 of x(n) to generate a byte. */
181 static void 202 static void
182 lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size) 203 lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 (void)win32_urandom((unsigned char *)secret, secret_size, 0); 281 (void)win32_urandom((unsigned char *)secret, secret_size, 0);
261 #else /* #ifdef MS_WINDOWS */ 282 #else /* #ifdef MS_WINDOWS */
262 # ifdef __VMS 283 # ifdef __VMS
263 vms_urandom((unsigned char *)secret, secret_size, 0); 284 vms_urandom((unsigned char *)secret, secret_size, 0);
264 # else 285 # else
265 dev_urandom_noraise((char*)secret, secret_size); 286 dev_urandom_noraise((char*)secret, secret_size);
266 # endif 287 # endif
267 #endif 288 #endif
268 } 289 }
269 } 290 }
291
292 void
293 _PyRandom_Fini(void)
294 {
295 #if !defined(MS_WINDOWS) && !defined(__VMS)
296 dev_urandom_close();
297 #endif
298 }
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+