3535#include <sys/resource.h>
3636#include <sys/time.h>
3737#include <sys/types.h>
38+ #include <sys/utsname.h>
3839#include <sys/wait.h>
3940#include <time.h>
4041#include <unistd.h>
42+
4143#ifdef __linux__
42- #include <sys/utsname.h>
44+ # ifdef __has_include
45+ # if __has_include (< linux /close_range .h > )
46+ # define HAS_CLOSE_RANGE_HEADERS
47+ # endif
48+ # elif defined(__FreeBSD__ )
49+ # ifdef CLOSE_RANGE_CLOEXEC
50+ # define HAS_CLOSE_RANGE_HEADERS
51+ # endif
52+ # endif
4353#endif
4454
4555// Well-known file descriptor numbers for reprl <-> child communication, child process side
@@ -60,6 +70,7 @@ static const int reprl_fds[] = {
6070#define REPRL_MAX_TIMEOUT_IN_MICROSECONDS ((uint64_t)(INT_MAX) * 1000)
6171
6272#define ARRAY_SIZE (arr ) (sizeof(arr) / sizeof((arr)[0]))
73+
6374static size_t min (size_t x , size_t y ) {
6475 return x < y ? x : y ;
6576}
@@ -93,29 +104,20 @@ static void free_string_array(char** arr)
93104 free (arr );
94105}
95106
96- static unsigned int getdtablesize_or_crash () {
107+ static int getdtablesize_or_crash () {
97108 const int tablesize = getdtablesize ();
98109 if (tablesize < 0 ) {
99110 fprintf (stderr , "getdtablesize() failed: %s. This likely means the system is borked.\n" ,
100111 strerror (errno ));
101- exit (-1 );
102- }
103-
104- return (unsigned int )tablesize ;
105- }
106-
107- static int fd_cast (unsigned int fd ) {
108- if (fd > INT_MAX ) {
109- fprintf (stderr , "File descriptor value %u is too large to fit into int. This likely means "
110- "the system is borked.\n" , fd );
111- exit (-1 );
112+ abort ();
112113 }
113114
114- return ( int ) fd ;
115+ return tablesize ;
115116}
116117
117118static bool system_supports_close_range () {
118- #ifdef __linux__
119+ #ifdef HAS_CLOSE_RANGE_HEADERS
120+ # ifdef __linux__
119121 struct utsname buffer ;
120122 int major , minor , patch ;
121123 (void )uname (& buffer ); // Linux uname can only throw EFAULT if buf is invalid.
@@ -125,11 +127,16 @@ static bool system_supports_close_range() {
125127 }
126128
127129 return major > 5 || (major == 5 && minor >= 9 );
128- #else
130+ # elif defined( __FreeBSD__ )
129131 // TODO: Technically, FreeBSD does support close_range, but I don't need support for it right
130- // now, so leaving this unimplemented.
132+ // now, so leaving this unimplemented. Don't have a platform to test on.
131133 // https://man.freebsd.org/cgi/man.cgi?close_range(2)
132134 return false;
135+ # else
136+ return false;
137+ # endif
138+ #else
139+ return false;
133140#endif
134141}
135142
@@ -141,13 +148,14 @@ static int fd_qsort_compare(const void* a, const void* b) {
141148
142149/// Fast path which uses close_range() to close ranges of fds.
143150static void close_all_non_reprl_fds_fast () {
151+ #ifdef HAS_CLOSE_RANGE_HEADERS
144152 // Unfortunately we cannot trust the reprl_fds array to be sorted since an accidental edit to
145153 // reprl_fds could have broken that assumption. So let's create a new sorted array. It's cheap
146154 // anyways.
147155 int sorted_reprl_fds [ARRAY_SIZE (reprl_fds ) + 2 ];
148156 sorted_reprl_fds [0 ] = 3 ; // Skip the well-known stdin, stdout, stderr fds.
149157 memcpy (sorted_reprl_fds + 1 , reprl_fds , sizeof (reprl_fds ));
150- sorted_reprl_fds [ARRAY_SIZE (sorted_reprl_fds ) - 1 ] = fd_cast ( getdtablesize_or_crash () );
158+ sorted_reprl_fds [ARRAY_SIZE (sorted_reprl_fds ) - 1 ] = getdtablesize_or_crash ();
151159 qsort (sorted_reprl_fds , ARRAY_SIZE (sorted_reprl_fds ), sizeof (int ), fd_qsort_compare );
152160
153161 // Cool, now we will iterate the sorted fds in ranges and close everything in between.
@@ -160,11 +168,16 @@ static void close_all_non_reprl_fds_fast() {
160168 }
161169 start_fd = end_fd + 1 ;
162170 }
171+ #else
172+ fprintf (stderr , "close_all_non_reprl_fds_fast() called on a system which does not support "
173+ "close_range(). This is likely a programming bug.\n" );
174+ abort ();
175+ #endif
163176}
164177
165178/// Fallback path which makes a close() syscall for each non-REPRL fd.
166179static void close_all_non_reprl_fds_slow () {
167- const int tablesize = fd_cast ( getdtablesize_or_crash () );
180+ const int tablesize = getdtablesize_or_crash ();
168181
169182 for (int i = 3 ; i < tablesize ; i ++ ) {
170183 bool is_reprl_fd = false;
@@ -183,11 +196,7 @@ static void close_all_non_reprl_fds_slow() {
183196
184197/// Close all file descriptors except the well-known REPRL and stdio fds.
185198static void close_all_non_reprl_fds () {
186- if (system_supports_close_range ()) {
187- close_all_non_reprl_fds_fast ();
188- } else {
189- close_all_non_reprl_fds_slow ();
190- }
199+ system_supports_close_range () ? close_all_non_reprl_fds_fast () : close_all_non_reprl_fds_slow ();
191200}
192201
193202// A unidirectional communication channel for larger amounts of data, up to a maximum size (REPRL_MAX_DATA_SIZE).
0 commit comments