4444#define POSIX_CALL (call ) do { if ((call) == -1) goto error; } while (0)
4545
4646
47- /* Maximum file descriptor, initialized on module load. */
48- static long max_fd ;
49-
50-
5147/* Given the gc module call gc.enable() and return 0 on success. */
5248static int
5349_enable_gc (PyObject * gc_module )
@@ -166,14 +162,39 @@ make_inheritable(PyObject *py_fds_to_keep, int errpipe_write)
166162}
167163
168164
169- /* Close all file descriptors in the range start_fd inclusive to
170- * end_fd exclusive except for those in py_fds_to_keep. If the
171- * range defined by [start_fd, end_fd) is large this will take a
172- * long time as it calls close() on EVERY possible fd.
165+ /* Get the maximum file descriptor that could be opened by this process.
166+ * This function is async signal safe for use between fork() and exec().
167+ */
168+ static long
169+ safe_get_max_fd (void )
170+ {
171+ long local_max_fd ;
172+ #if defined(__NetBSD__ )
173+ local_max_fd = fcntl (0 , F_MAXFD );
174+ if (local_max_fd >= 0 )
175+ return local_max_fd ;
176+ #endif
177+ #ifdef _SC_OPEN_MAX
178+ local_max_fd = sysconf (_SC_OPEN_MAX );
179+ if (local_max_fd == -1 )
180+ #endif
181+ local_max_fd = 256 ; /* Matches legacy Lib/subprocess.py behavior. */
182+ return local_max_fd ;
183+ }
184+
185+
186+ /* Close all file descriptors in the range from start_fd and higher
187+ * except for those in py_fds_to_keep. If the range defined by
188+ * [start_fd, safe_get_max_fd()) is large this will take a long
189+ * time as it calls close() on EVERY possible fd.
190+ *
191+ * It isn't possible to know for sure what the max fd to go up to
192+ * is for processes with the capability of raising their maximum.
173193 */
174194static void
175- _close_fds_by_brute_force (int start_fd , int end_fd , PyObject * py_fds_to_keep )
195+ _close_fds_by_brute_force (long start_fd , PyObject * py_fds_to_keep )
176196{
197+ long end_fd = safe_get_max_fd ();
177198 Py_ssize_t num_fds_to_keep = PySequence_Length (py_fds_to_keep );
178199 Py_ssize_t keep_seq_idx ;
179200 int fd_num ;
@@ -229,16 +250,14 @@ struct linux_dirent64 {
229250 * it with some cpp #define magic to work on other OSes as well if you want.
230251 */
231252static void
232- _close_open_fd_range_safe (int start_fd , int end_fd , PyObject * py_fds_to_keep )
253+ _close_open_fds_safe (int start_fd , PyObject * py_fds_to_keep )
233254{
234255 int fd_dir_fd ;
235- if (start_fd >= end_fd )
236- return ;
237256
238257 fd_dir_fd = _Py_open (FD_DIR , O_RDONLY );
239258 if (fd_dir_fd == -1 ) {
240259 /* No way to get a list of open fds. */
241- _close_fds_by_brute_force (start_fd , end_fd , py_fds_to_keep );
260+ _close_fds_by_brute_force (start_fd , py_fds_to_keep );
242261 return ;
243262 } else {
244263 char buffer [sizeof (struct linux_dirent64 )];
@@ -253,23 +272,23 @@ _close_open_fd_range_safe(int start_fd, int end_fd, PyObject* py_fds_to_keep)
253272 entry = (struct linux_dirent64 * )(buffer + offset );
254273 if ((fd = _pos_int_from_ascii (entry -> d_name )) < 0 )
255274 continue ; /* Not a number. */
256- if (fd != fd_dir_fd && fd >= start_fd && fd < end_fd &&
275+ if (fd != fd_dir_fd && fd >= start_fd &&
257276 !_is_fd_in_sorted_fd_sequence (fd , py_fds_to_keep )) {
258277 while (close (fd ) < 0 && errno == EINTR );
259278 }
260279 }
261280 }
262- close (fd_dir_fd );
281+ while ( close (fd_dir_fd ) < 0 && errno == EINTR );
263282 }
264283}
265284
266- #define _close_open_fd_range _close_open_fd_range_safe
285+ #define _close_open_fds _close_open_fds_safe
267286
268287#else /* NOT (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)) */
269288
270289
271- /* Close all open file descriptors in the range start_fd inclusive to end_fd
272- * exclusive. Do not close any in the sorted py_fds_to_keep list.
290+ /* Close all open file descriptors from start_fd and higher.
291+ * Do not close any in the sorted py_fds_to_keep list.
273292 *
274293 * This function violates the strict use of async signal safe functions. :(
275294 * It calls opendir(), readdir() and closedir(). Of these, the one most
@@ -282,26 +301,20 @@ _close_open_fd_range_safe(int start_fd, int end_fd, PyObject* py_fds_to_keep)
282301 * http://womble.decadent.org.uk/readdir_r-advisory.html
283302 */
284303static void
285- _close_open_fd_range_maybe_unsafe (int start_fd , int end_fd ,
286- PyObject * py_fds_to_keep )
304+ _close_open_fds_maybe_unsafe (long start_fd , PyObject * py_fds_to_keep )
287305{
288306 DIR * proc_fd_dir ;
289307#ifndef HAVE_DIRFD
290- while (_is_fd_in_sorted_fd_sequence (start_fd , py_fds_to_keep ) &&
291- (start_fd < end_fd )) {
308+ while (_is_fd_in_sorted_fd_sequence (start_fd , py_fds_to_keep )) {
292309 ++ start_fd ;
293310 }
294- if (start_fd >= end_fd )
295- return ;
296311 /* Close our lowest fd before we call opendir so that it is likely to
297312 * reuse that fd otherwise we might close opendir's file descriptor in
298313 * our loop. This trick assumes that fd's are allocated on a lowest
299314 * available basis. */
300315 while (close (start_fd ) < 0 && errno == EINTR );
301316 ++ start_fd ;
302317#endif
303- if (start_fd >= end_fd )
304- return ;
305318
306319#if defined(__FreeBSD__ )
307320 if (!_is_fdescfs_mounted_on_dev_fd ())
@@ -311,7 +324,7 @@ _close_open_fd_range_maybe_unsafe(int start_fd, int end_fd,
311324 proc_fd_dir = opendir (FD_DIR );
312325 if (!proc_fd_dir ) {
313326 /* No way to get a list of open fds. */
314- _close_fds_by_brute_force (start_fd , end_fd , py_fds_to_keep );
327+ _close_fds_by_brute_force (start_fd , py_fds_to_keep );
315328 } else {
316329 struct dirent * dir_entry ;
317330#ifdef HAVE_DIRFD
@@ -324,21 +337,21 @@ _close_open_fd_range_maybe_unsafe(int start_fd, int end_fd,
324337 int fd ;
325338 if ((fd = _pos_int_from_ascii (dir_entry -> d_name )) < 0 )
326339 continue ; /* Not a number. */
327- if (fd != fd_used_by_opendir && fd >= start_fd && fd < end_fd &&
340+ if (fd != fd_used_by_opendir && fd >= start_fd &&
328341 !_is_fd_in_sorted_fd_sequence (fd , py_fds_to_keep )) {
329342 while (close (fd ) < 0 && errno == EINTR );
330343 }
331344 errno = 0 ;
332345 }
333346 if (errno ) {
334347 /* readdir error, revert behavior. Highly Unlikely. */
335- _close_fds_by_brute_force (start_fd , end_fd , py_fds_to_keep );
348+ _close_fds_by_brute_force (start_fd , py_fds_to_keep );
336349 }
337350 closedir (proc_fd_dir );
338351 }
339352}
340353
341- #define _close_open_fd_range _close_open_fd_range_maybe_unsafe
354+ #define _close_open_fds _close_open_fds_maybe_unsafe
342355
343356#endif /* else NOT (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)) */
344357
@@ -457,14 +470,8 @@ child_exec(char *const exec_array[],
457470
458471 /* close FDs after executing preexec_fn, which might open FDs */
459472 if (close_fds ) {
460- int local_max_fd = max_fd ;
461- #if defined(__NetBSD__ )
462- local_max_fd = fcntl (0 , F_MAXFD );
463- if (local_max_fd < 0 )
464- local_max_fd = max_fd ;
465- #endif
466473 /* TODO HP-UX could use pstat_getproc() if anyone cares about it. */
467- _close_open_fd_range ( 3 , local_max_fd , py_fds_to_keep );
474+ _close_open_fds ( 3 , py_fds_to_keep );
468475 }
469476
470477 /* This loop matches the Lib/os.py _execvpe()'s PATH search when */
@@ -759,11 +766,5 @@ static struct PyModuleDef _posixsubprocessmodule = {
759766PyMODINIT_FUNC
760767PyInit__posixsubprocess (void )
761768{
762- #ifdef _SC_OPEN_MAX
763- max_fd = sysconf (_SC_OPEN_MAX );
764- if (max_fd == -1 )
765- #endif
766- max_fd = 256 ; /* Matches Lib/subprocess.py */
767-
768769 return PyModule_Create (& _posixsubprocessmodule );
769770}
0 commit comments