34
34
#include <string.h>
35
35
#include <fcntl.h>
36
36
#include <pthread.h>
37
-
37
+ #include <dirent.h>
38
38
#include <stdio.h>
39
39
40
+ #if __has_include (< linux /close_range .h > )
41
+ #include <linux/close_range.h>
42
+ #endif
43
+
44
+ #endif // TARGET_OS_WINDOWS
45
+
40
46
#if __has_include (< crt_externs .h > )
41
47
#include <crt_externs.h>
42
48
#elif defined(_WIN32)
@@ -50,6 +56,7 @@ extern char **environ;
50
56
#include <mach/vm_page_size.h>
51
57
#endif
52
58
59
+ #if !TARGET_OS_WINDOWS
53
60
int _was_process_exited (int status ) {
54
61
return WIFEXITED (status );
55
62
}
@@ -70,24 +77,8 @@ int _was_process_suspended(int status) {
70
77
return WIFSTOPPED (status );
71
78
}
72
79
73
- #if TARGET_OS_LINUX
74
- #include <stdio.h>
75
-
76
- int _shims_snprintf (
77
- char * _Nonnull str ,
78
- int len ,
79
- const char * _Nonnull format ,
80
- char * _Nonnull str1 ,
81
- char * _Nonnull str2
82
- ) {
83
- return snprintf (str , len , format , str1 , str2 );
84
- }
85
-
86
- int _pidfd_send_signal (int pidfd , int signal ) {
87
- return syscall (SYS_pidfd_send_signal , pidfd , signal , NULL , 0 );
88
- }
80
+ #endif // !TARGET_OS_WINDOWS
89
81
90
- #endif
91
82
92
83
#if __has_include (< mach /vm_page_size .h > )
93
84
vm_size_t _subprocess_vm_size (void ) {
@@ -96,40 +87,6 @@ vm_size_t _subprocess_vm_size(void) {
96
87
}
97
88
#endif
98
89
99
- // MARK: - Private Helpers
100
- static pthread_mutex_t _subprocess_fork_lock = PTHREAD_MUTEX_INITIALIZER ;
101
-
102
- static int _subprocess_block_everything_but_something_went_seriously_wrong_signals (sigset_t * old_mask ) {
103
- sigset_t mask ;
104
- int r = 0 ;
105
- r |= sigfillset (& mask );
106
- r |= sigdelset (& mask , SIGABRT );
107
- r |= sigdelset (& mask , SIGBUS );
108
- r |= sigdelset (& mask , SIGFPE );
109
- r |= sigdelset (& mask , SIGILL );
110
- r |= sigdelset (& mask , SIGKILL );
111
- r |= sigdelset (& mask , SIGSEGV );
112
- r |= sigdelset (& mask , SIGSTOP );
113
- r |= sigdelset (& mask , SIGSYS );
114
- r |= sigdelset (& mask , SIGTRAP );
115
-
116
- r |= pthread_sigmask (SIG_BLOCK , & mask , old_mask );
117
- return r ;
118
- }
119
-
120
- #define _subprocess_precondition (__cond ) do { \
121
- int eval = (__cond); \
122
- if (!eval) { \
123
- __builtin_trap(); \
124
- } \
125
- } while(0)
126
-
127
- #if __DARWIN_NSIG
128
- # define _SUBPROCESS_SIG_MAX __DARWIN_NSIG
129
- #else
130
- # define _SUBPROCESS_SIG_MAX 32
131
- #endif
132
-
133
90
134
91
// MARK: - Darwin (posix_spawn)
135
92
#if TARGET_OS_MAC
@@ -336,6 +293,100 @@ static int _clone3(int *pidfd) {
336
293
return syscall (SYS_clone3 , & args , sizeof (args ));
337
294
}
338
295
296
+ static pthread_mutex_t _subprocess_fork_lock = PTHREAD_MUTEX_INITIALIZER ;
297
+
298
+ static int _subprocess_make_critical_mask (sigset_t * old_mask ) {
299
+ sigset_t mask ;
300
+ int r = 0 ;
301
+ r |= sigfillset (& mask );
302
+ r |= sigdelset (& mask , SIGABRT );
303
+ r |= sigdelset (& mask , SIGBUS );
304
+ r |= sigdelset (& mask , SIGFPE );
305
+ r |= sigdelset (& mask , SIGILL );
306
+ r |= sigdelset (& mask , SIGKILL );
307
+ r |= sigdelset (& mask , SIGSEGV );
308
+ r |= sigdelset (& mask , SIGSTOP );
309
+ r |= sigdelset (& mask , SIGSYS );
310
+ r |= sigdelset (& mask , SIGTRAP );
311
+
312
+ r |= pthread_sigmask (SIG_BLOCK , & mask , old_mask );
313
+ return r ;
314
+ }
315
+
316
+ #define _subprocess_precondition (__cond ) do { \
317
+ int eval = (__cond); \
318
+ if (!eval) { \
319
+ __builtin_trap(); \
320
+ } \
321
+ } while(0)
322
+
323
+ #if __DARWIN_NSIG
324
+ # define _SUBPROCESS_SIG_MAX __DARWIN_NSIG
325
+ #else
326
+ # define _SUBPROCESS_SIG_MAX 32
327
+ #endif
328
+
329
+ int _shims_snprintf (
330
+ char * _Nonnull str ,
331
+ int len ,
332
+ const char * _Nonnull format ,
333
+ char * _Nonnull str1 ,
334
+ char * _Nonnull str2
335
+ ) {
336
+ return snprintf (str , len , format , str1 , str2 );
337
+ }
338
+
339
+ static int _positive_int_parse (const char * str ) {
340
+ char * end ;
341
+ long value = strtol (str , & end , 10 );
342
+ if (end == str ) {
343
+ // No digits found
344
+ return -1 ;
345
+ }
346
+ if (errno == ERANGE || val <= 0 || val > INT_MAX ) {
347
+ // Out of range
348
+ return -1 ;
349
+ }
350
+ return (int )value ;
351
+ }
352
+
353
+ static int _highest_possibly_open_fd_dir (const char * fd_dir ) {
354
+ int highest_fd_so_far = 0 ;
355
+ DIR * dir_ptr = opendir (fd_dir );
356
+ if (dir_ptr == NULL ) {
357
+ return -1 ;
358
+ }
359
+
360
+ struct dirent * dir_entry = NULL ;
361
+ while ((dir_entry = readdir (dir_ptr )) != NULL ) {
362
+ char * entry_name = dir_entry -> d_name ;
363
+ int number = _positive_int_parse (entry_name );
364
+ if (number > (long )highest_fd_so_far ) {
365
+ highest_fd_so_far = number ;
366
+ }
367
+ }
368
+
369
+ closedir (dir_ptr );
370
+ return highest_fd_so_far ;
371
+ }
372
+
373
+ static int _highest_possibly_open_fd (void ) {
374
+ #if defined(__APPLE__ )
375
+ int hi = _highest_possibly_open_fd_dir ("/dev/fd" );
376
+ if (hi < 0 ) {
377
+ hi = getdtablesize ();
378
+ }
379
+ #elif defined(__linux__ )
380
+ int hi = _highest_possibly_open_fd_dir ("/proc/self/fd" );
381
+ if (hi < 0 ) {
382
+ hi = getdtablesize ();
383
+ }
384
+ #else
385
+ int hi = getdtablesize ();
386
+ #endif
387
+ return hi ;
388
+ }
389
+
339
390
int _subprocess_fork_exec (
340
391
pid_t * _Nonnull pid ,
341
392
int * _Nonnull pidfd ,
@@ -395,7 +446,7 @@ int _subprocess_fork_exec(
395
446
_subprocess_precondition (rc == 0 );
396
447
// Block all signals on this thread
397
448
sigset_t old_sigmask ;
398
- rc = _subprocess_block_everything_but_something_went_seriously_wrong_signals (& old_sigmask );
449
+ rc = _subprocess_make_critical_mask (& old_sigmask );
399
450
if (rc != 0 ) {
400
451
close (pipefd [0 ]);
401
452
close (pipefd [1 ]);
@@ -515,20 +566,22 @@ int _subprocess_fork_exec(
515
566
if (rc < 0 ) {
516
567
write_error_and_exit ;
517
568
}
518
-
519
- // Close parent side
520
- if (file_descriptors [1 ] >= 0 ) {
521
- rc = close (file_descriptors [1 ]);
522
- }
523
- if (file_descriptors [3 ] >= 0 ) {
524
- rc = close (file_descriptors [3 ]);
525
- }
526
- if (file_descriptors [5 ] >= 0 ) {
527
- rc = close (file_descriptors [5 ]);
528
- }
529
-
530
- if (rc < 0 ) {
531
- write_error_and_exit ;
569
+ // Close all other file descriptors
570
+ rc = -1 ;
571
+ errno = ENOSYS ;
572
+ #if __has_include (< linux /close_range .h > ) || defined(__FreeBSD__ )
573
+ // We must NOT close pipefd[1] for writing errors
574
+ rc = close_range (STDERR_FILENO + 1 , pipefd [1 ] - 1 , 0 );
575
+ rc |= close_range (pipefd [1 ] + 1 , ~0U , 0 );
576
+ #endif
577
+ if (rc != 0 ) {
578
+ // close_range failed (or doesn't exist), fall back to close()
579
+ for (int fd = STDERR_FILENO + 1 ; fd < _highest_possibly_open_fd (); fd ++ ) {
580
+ // We must NOT close pipefd[1] for writing errors
581
+ if (fd != pipefd [1 ]) {
582
+ close (fd );
583
+ }
584
+ }
532
585
}
533
586
534
587
// Run custom configuratior
@@ -606,8 +659,6 @@ int _subprocess_fork_exec(
606
659
607
660
#endif // TARGET_OS_LINUX
608
661
609
- #endif // !TARGET_OS_WINDOWS
610
-
611
662
#pragma mark - Environment Locking
612
663
613
664
#if __has_include (< libc_private .h > )
0 commit comments