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
@@ -351,6 +308,100 @@ static int _clone3(int *pidfd) {
351
308
return syscall (SYS_clone3 , & args , sizeof (args ));
352
309
}
353
310
311
+ static pthread_mutex_t _subprocess_fork_lock = PTHREAD_MUTEX_INITIALIZER ;
312
+
313
+ static int _subprocess_make_critical_mask (sigset_t * old_mask ) {
314
+ sigset_t mask ;
315
+ int r = 0 ;
316
+ r |= sigfillset (& mask );
317
+ r |= sigdelset (& mask , SIGABRT );
318
+ r |= sigdelset (& mask , SIGBUS );
319
+ r |= sigdelset (& mask , SIGFPE );
320
+ r |= sigdelset (& mask , SIGILL );
321
+ r |= sigdelset (& mask , SIGKILL );
322
+ r |= sigdelset (& mask , SIGSEGV );
323
+ r |= sigdelset (& mask , SIGSTOP );
324
+ r |= sigdelset (& mask , SIGSYS );
325
+ r |= sigdelset (& mask , SIGTRAP );
326
+
327
+ r |= pthread_sigmask (SIG_BLOCK , & mask , old_mask );
328
+ return r ;
329
+ }
330
+
331
+ #define _subprocess_precondition (__cond ) do { \
332
+ int eval = (__cond); \
333
+ if (!eval) { \
334
+ __builtin_trap(); \
335
+ } \
336
+ } while(0)
337
+
338
+ #if __DARWIN_NSIG
339
+ # define _SUBPROCESS_SIG_MAX __DARWIN_NSIG
340
+ #else
341
+ # define _SUBPROCESS_SIG_MAX 32
342
+ #endif
343
+
344
+ int _shims_snprintf (
345
+ char * _Nonnull str ,
346
+ int len ,
347
+ const char * _Nonnull format ,
348
+ char * _Nonnull str1 ,
349
+ char * _Nonnull str2
350
+ ) {
351
+ return snprintf (str , len , format , str1 , str2 );
352
+ }
353
+
354
+ static int _positive_int_parse (const char * str ) {
355
+ char * end ;
356
+ long value = strtol (str , & end , 10 );
357
+ if (end == str ) {
358
+ // No digits found
359
+ return -1 ;
360
+ }
361
+ if (errno == ERANGE || val <= 0 || val > INT_MAX ) {
362
+ // Out of range
363
+ return -1 ;
364
+ }
365
+ return (int )value ;
366
+ }
367
+
368
+ static int _highest_possibly_open_fd_dir (const char * fd_dir ) {
369
+ int highest_fd_so_far = 0 ;
370
+ DIR * dir_ptr = opendir (fd_dir );
371
+ if (dir_ptr == NULL ) {
372
+ return -1 ;
373
+ }
374
+
375
+ struct dirent * dir_entry = NULL ;
376
+ while ((dir_entry = readdir (dir_ptr )) != NULL ) {
377
+ char * entry_name = dir_entry -> d_name ;
378
+ int number = _positive_int_parse (entry_name );
379
+ if (number > (long )highest_fd_so_far ) {
380
+ highest_fd_so_far = number ;
381
+ }
382
+ }
383
+
384
+ closedir (dir_ptr );
385
+ return highest_fd_so_far ;
386
+ }
387
+
388
+ static int _highest_possibly_open_fd (void ) {
389
+ #if defined(__APPLE__ )
390
+ int hi = _highest_possibly_open_fd_dir ("/dev/fd" );
391
+ if (hi < 0 ) {
392
+ hi = getdtablesize ();
393
+ }
394
+ #elif defined(__linux__ )
395
+ int hi = _highest_possibly_open_fd_dir ("/proc/self/fd" );
396
+ if (hi < 0 ) {
397
+ hi = getdtablesize ();
398
+ }
399
+ #else
400
+ int hi = getdtablesize ();
401
+ #endif
402
+ return hi ;
403
+ }
404
+
354
405
int _subprocess_fork_exec (
355
406
pid_t * _Nonnull pid ,
356
407
int * _Nonnull pidfd ,
@@ -410,7 +461,7 @@ int _subprocess_fork_exec(
410
461
_subprocess_precondition (rc == 0 );
411
462
// Block all signals on this thread
412
463
sigset_t old_sigmask ;
413
- rc = _subprocess_block_everything_but_something_went_seriously_wrong_signals (& old_sigmask );
464
+ rc = _subprocess_make_critical_mask (& old_sigmask );
414
465
if (rc != 0 ) {
415
466
close (pipefd [0 ]);
416
467
close (pipefd [1 ]);
@@ -530,20 +581,22 @@ int _subprocess_fork_exec(
530
581
if (rc < 0 ) {
531
582
write_error_and_exit ;
532
583
}
533
-
534
- // Close parent side
535
- if (file_descriptors [1 ] >= 0 ) {
536
- rc = close (file_descriptors [1 ]);
537
- }
538
- if (file_descriptors [3 ] >= 0 ) {
539
- rc = close (file_descriptors [3 ]);
540
- }
541
- if (file_descriptors [5 ] >= 0 ) {
542
- rc = close (file_descriptors [5 ]);
543
- }
544
-
545
- if (rc < 0 ) {
546
- write_error_and_exit ;
584
+ // Close all other file descriptors
585
+ rc = -1 ;
586
+ errno = ENOSYS ;
587
+ #if __has_include (< linux /close_range .h > ) || defined(__FreeBSD__ )
588
+ // We must NOT close pipefd[1] for writing errors
589
+ rc = close_range (STDERR_FILENO + 1 , pipefd [1 ] - 1 , 0 );
590
+ rc |= close_range (pipefd [1 ] + 1 , ~0U , 0 );
591
+ #endif
592
+ if (rc != 0 ) {
593
+ // close_range failed (or doesn't exist), fall back to close()
594
+ for (int fd = STDERR_FILENO + 1 ; fd < _highest_possibly_open_fd (); fd ++ ) {
595
+ // We must NOT close pipefd[1] for writing errors
596
+ if (fd != pipefd [1 ]) {
597
+ close (fd );
598
+ }
599
+ }
547
600
}
548
601
549
602
// Run custom configuratior
@@ -621,8 +674,6 @@ int _subprocess_fork_exec(
621
674
622
675
#endif // TARGET_OS_LINUX
623
676
624
- #endif // !TARGET_OS_WINDOWS
625
-
626
677
#pragma mark - Environment Locking
627
678
628
679
#if __has_include (< libc_private .h > )
0 commit comments