@@ -65,13 +65,9 @@ Documentation for C++ subprocessing library.
65
65
66
66
extern " C" {
67
67
#ifdef __USING_WINDOWS__
68
- #include < Windows .h>
68
+ #include < windows .h>
69
69
#include < io.h>
70
70
#include < cwchar>
71
-
72
- #define close _close
73
- #define open _open
74
- #define fileno _fileno
75
71
#else
76
72
#include < sys/wait.h>
77
73
#include < unistd.h>
@@ -81,6 +77,22 @@ extern "C" {
81
77
#include < sys/types.h>
82
78
}
83
79
80
+ // The Microsoft C++ compiler issues deprecation warnings
81
+ // for the standard POSIX function names.
82
+ // Its preferred implementations have a leading underscore.
83
+ // See: https://learn.microsoft.com/en-us/cpp/c-runtime-library/compatibility.
84
+ #if (defined _MSC_VER)
85
+ #define subprocess_close _close
86
+ #define subprocess_fileno _fileno
87
+ #define subprocess_open _open
88
+ #define subprocess_write _write
89
+ #else
90
+ #define subprocess_close close
91
+ #define subprocess_fileno fileno
92
+ #define subprocess_open open
93
+ #define subprocess_write write
94
+ #endif
95
+
84
96
/* !
85
97
* Getting started with reading this source code.
86
98
* The source is mainly divided into four parts:
@@ -159,6 +171,7 @@ class OSError: public std::runtime_error
159
171
// --------------------------------------------------------------------
160
172
namespace util
161
173
{
174
+ #ifdef __USING_WINDOWS__
162
175
inline void quote_argument (const std::wstring &argument, std::wstring &command_line,
163
176
bool force)
164
177
{
@@ -169,7 +182,7 @@ namespace util
169
182
//
170
183
171
184
if (force == false && argument.empty () == false &&
172
- argument.find_first_of (L" \t\n\v\" " ) == argument.npos ) {
185
+ argument.find_first_of (L" \t\n\v " ) == argument.npos ) {
173
186
command_line.append (argument);
174
187
}
175
188
else {
@@ -219,7 +232,6 @@ namespace util
219
232
}
220
233
}
221
234
222
- #ifdef __USING_WINDOWS__
223
235
inline std::string get_last_error (DWORD errorMessageID)
224
236
{
225
237
if (errorMessageID == 0 )
@@ -264,7 +276,7 @@ namespace util
264
276
265
277
FILE *fp = _fdopen (os_fhandle, mode);
266
278
if (fp == 0 ) {
267
- _close (os_fhandle);
279
+ subprocess_close (os_fhandle);
268
280
throw OSError (" _fdopen" , 0 );
269
281
}
270
282
@@ -334,10 +346,14 @@ namespace util
334
346
void set_clo_on_exec (int fd, bool set = true )
335
347
{
336
348
int flags = fcntl (fd, F_GETFD, 0 );
349
+ if (flags == -1 ) {
350
+ throw OSError (" fcntl F_GETFD failed" , errno);
351
+ }
337
352
if (set) flags |= FD_CLOEXEC;
338
353
else flags &= ~FD_CLOEXEC;
339
- // TODO: should check for errors
340
- fcntl (fd, F_SETFD, flags);
354
+ if (fcntl (fd, F_SETFD, flags) == -1 ) {
355
+ throw OSError (" fcntl F_SETFD failed" , errno);
356
+ }
341
357
}
342
358
343
359
@@ -383,7 +399,7 @@ namespace util
383
399
{
384
400
size_t nwritten = 0 ;
385
401
while (nwritten < length) {
386
- int written = write (fd, buf + nwritten, length - nwritten);
402
+ int written = subprocess_write (fd, buf + nwritten, length - nwritten);
387
403
if (written == -1 ) return -1 ;
388
404
nwritten += written;
389
405
}
@@ -411,7 +427,7 @@ namespace util
411
427
#ifdef __USING_WINDOWS__
412
428
return (int )fread (buf, 1 , read_upto, fp);
413
429
#else
414
- int fd = fileno (fp);
430
+ int fd = subprocess_fileno (fp);
415
431
int rbytes = 0 ;
416
432
int eintr_cnter = 0 ;
417
433
@@ -527,7 +543,7 @@ struct string_arg
527
543
{
528
544
string_arg (const char * arg): arg_value(arg) {}
529
545
string_arg (std::string&& arg): arg_value(std::move(arg)) {}
530
- string_arg (std::string arg): arg_value(std::move( arg) ) {}
546
+ string_arg (const std::string& arg): arg_value(arg) {}
531
547
std::string arg_value;
532
548
};
533
549
@@ -573,10 +589,10 @@ struct input
573
589
explicit input (int fd): rd_ch_(fd) {}
574
590
575
591
// FILE pointer.
576
- explicit input (FILE* fp):input(fileno (fp)) { assert (fp); }
592
+ explicit input (FILE* fp):input(subprocess_fileno (fp)) { assert (fp); }
577
593
578
594
explicit input (const char * filename) {
579
- int fd = open (filename, O_RDONLY);
595
+ int fd = subprocess_open (filename, O_RDONLY);
580
596
if (fd == -1 ) throw OSError (" File not found: " , errno);
581
597
rd_ch_ = fd;
582
598
}
@@ -606,10 +622,10 @@ struct output
606
622
{
607
623
explicit output (int fd): wr_ch_(fd) {}
608
624
609
- explicit output (FILE* fp):output(fileno (fp)) { assert (fp); }
625
+ explicit output (FILE* fp):output(subprocess_fileno (fp)) { assert (fp); }
610
626
611
627
explicit output (const char * filename) {
612
- int fd = open (filename, O_APPEND | O_CREAT | O_RDWR, 0640 );
628
+ int fd = subprocess_open (filename, O_APPEND | O_CREAT | O_RDWR, 0640 );
613
629
if (fd == -1 ) throw OSError (" File not found: " , errno);
614
630
wr_ch_ = fd;
615
631
}
@@ -637,10 +653,10 @@ struct error
637
653
{
638
654
explicit error (int fd): wr_ch_(fd) {}
639
655
640
- explicit error (FILE* fp):error(fileno (fp)) { assert (fp); }
656
+ explicit error (FILE* fp):error(subprocess_fileno (fp)) { assert (fp); }
641
657
642
658
explicit error (const char * filename) {
643
- int fd = open (filename, O_APPEND | O_CREAT | O_RDWR, 0640 );
659
+ int fd = subprocess_open (filename, O_APPEND | O_CREAT | O_RDWR, 0640 );
644
660
if (fd == -1 ) throw OSError (" File not found: " , errno);
645
661
wr_ch_ = fd;
646
662
}
@@ -758,7 +774,10 @@ class Communication
758
774
public:
759
775
Communication (Streams* stream): stream_(stream)
760
776
{}
761
- void operator =(const Communication&) = delete ;
777
+ Communication (const Communication&) = delete ;
778
+ Communication& operator =(const Communication&) = delete ;
779
+ Communication (Communication&&) = default ;
780
+ Communication& operator =(Communication&&) = default ;
762
781
public:
763
782
int send (const char * msg, size_t length);
764
783
int send (const std::vector<char >& msg);
@@ -795,36 +814,39 @@ class Streams
795
814
{
796
815
public:
797
816
Streams ():comm_(this ) {}
798
- void operator =(const Streams&) = delete ;
817
+ Streams (const Streams&) = delete ;
818
+ Streams& operator =(const Streams&) = delete ;
819
+ Streams (Streams&&) = default ;
820
+ Streams& operator =(Streams&&) = default ;
799
821
800
822
public:
801
823
void setup_comm_channels ();
802
824
803
825
void cleanup_fds ()
804
826
{
805
827
if (write_to_child_ != -1 && read_from_parent_ != -1 ) {
806
- close (write_to_child_);
828
+ subprocess_close (write_to_child_);
807
829
}
808
830
if (write_to_parent_ != -1 && read_from_child_ != -1 ) {
809
- close (read_from_child_);
831
+ subprocess_close (read_from_child_);
810
832
}
811
833
if (err_write_ != -1 && err_read_ != -1 ) {
812
- close (err_read_);
834
+ subprocess_close (err_read_);
813
835
}
814
836
}
815
837
816
838
void close_parent_fds ()
817
839
{
818
- if (write_to_child_ != -1 ) close (write_to_child_);
819
- if (read_from_child_ != -1 ) close (read_from_child_);
820
- if (err_read_ != -1 ) close (err_read_);
840
+ if (write_to_child_ != -1 ) subprocess_close (write_to_child_);
841
+ if (read_from_child_ != -1 ) subprocess_close (read_from_child_);
842
+ if (err_read_ != -1 ) subprocess_close (err_read_);
821
843
}
822
844
823
845
void close_child_fds ()
824
846
{
825
- if (write_to_parent_ != -1 ) close (write_to_parent_);
826
- if (read_from_parent_ != -1 ) close (read_from_parent_);
827
- if (err_write_ != -1 ) close (err_write_);
847
+ if (write_to_parent_ != -1 ) subprocess_close (write_to_parent_);
848
+ if (read_from_parent_ != -1 ) subprocess_close (read_from_parent_);
849
+ if (err_write_ != -1 ) subprocess_close (err_write_);
828
850
}
829
851
830
852
FILE* input () { return input_.get (); }
@@ -1043,7 +1065,19 @@ inline int Popen::wait() noexcept(false)
1043
1065
#ifdef __USING_WINDOWS__
1044
1066
int ret = WaitForSingleObject (process_handle_, INFINITE);
1045
1067
1046
- return 0 ;
1068
+ // WaitForSingleObject with INFINITE should only return when process has signaled
1069
+ if (ret != WAIT_OBJECT_0) {
1070
+ throw OSError (" Unexpected return code from WaitForSingleObject" , 0 );
1071
+ }
1072
+
1073
+ DWORD dretcode_;
1074
+
1075
+ if (FALSE == GetExitCodeProcess (process_handle_, &dretcode_))
1076
+ throw OSError (" Failed during call to GetExitCodeProcess" , 0 );
1077
+
1078
+ CloseHandle (process_handle_);
1079
+
1080
+ return (int )dretcode_;
1047
1081
#else
1048
1082
int ret, status;
1049
1083
std::tie (ret, status) = util::wait_for_child_exit (child_pid_);
@@ -1156,8 +1190,8 @@ inline void Popen::execute_process() noexcept(false)
1156
1190
child_pid_ = fork ();
1157
1191
1158
1192
if (child_pid_ < 0 ) {
1159
- close (err_rd_pipe);
1160
- close (err_wr_pipe);
1193
+ subprocess_close (err_rd_pipe);
1194
+ subprocess_close (err_wr_pipe);
1161
1195
throw OSError (" fork failed" , errno);
1162
1196
}
1163
1197
@@ -1167,25 +1201,27 @@ inline void Popen::execute_process() noexcept(false)
1167
1201
stream_.close_parent_fds ();
1168
1202
1169
1203
// Close the read end of the error pipe
1170
- close (err_rd_pipe);
1204
+ subprocess_close (err_rd_pipe);
1171
1205
1172
1206
detail::Child chld (this , err_wr_pipe);
1173
1207
chld.execute_child ();
1174
1208
}
1175
1209
else
1176
1210
{
1177
- close (err_wr_pipe);// close child side of pipe, else get stuck in read below
1211
+ subprocess_close (err_wr_pipe);// close child side of pipe, else get stuck in read below
1178
1212
1179
1213
stream_.close_child_fds ();
1180
1214
1181
1215
try {
1182
1216
char err_buf[SP_MAX_ERR_BUF_SIZ] = {0 ,};
1183
1217
1184
- int read_bytes = util::read_atmost_n (
1185
- fdopen (err_rd_pipe, " r" ),
1186
- err_buf,
1187
- SP_MAX_ERR_BUF_SIZ);
1188
- close (err_rd_pipe);
1218
+ FILE* err_fp = fdopen (err_rd_pipe, " r" );
1219
+ if (!err_fp) {
1220
+ subprocess_close (err_rd_pipe);
1221
+ throw OSError (" fdopen failed" , errno);
1222
+ }
1223
+ int read_bytes = util::read_atmost_n (err_fp, err_buf, SP_MAX_ERR_BUF_SIZ);
1224
+ fclose (err_fp);
1189
1225
1190
1226
if (read_bytes || strlen (err_buf)) {
1191
1227
// Call waitpid to reap the child process
@@ -1271,13 +1307,13 @@ namespace detail {
1271
1307
1272
1308
// Close the duped descriptors
1273
1309
if (stream.read_from_parent_ != -1 && stream.read_from_parent_ > 2 )
1274
- close (stream.read_from_parent_ );
1310
+ subprocess_close (stream.read_from_parent_ );
1275
1311
1276
1312
if (stream.write_to_parent_ != -1 && stream.write_to_parent_ > 2 )
1277
- close (stream.write_to_parent_ );
1313
+ subprocess_close (stream.write_to_parent_ );
1278
1314
1279
1315
if (stream.err_write_ != -1 && stream.err_write_ > 2 )
1280
- close (stream.err_write_ );
1316
+ subprocess_close (stream.err_write_ );
1281
1317
1282
1318
// Replace the current image with the executable
1283
1319
sys_ret = execvp (parent_->exe_name_ .c_str (), parent_->cargv_ .data ());
@@ -1304,15 +1340,15 @@ namespace detail {
1304
1340
#ifdef __USING_WINDOWS__
1305
1341
util::configure_pipe (&this ->g_hChildStd_IN_Rd , &this ->g_hChildStd_IN_Wr , &this ->g_hChildStd_IN_Wr );
1306
1342
this ->input (util::file_from_handle (this ->g_hChildStd_IN_Wr , " w" ));
1307
- this ->write_to_child_ = _fileno (this ->input ());
1343
+ this ->write_to_child_ = subprocess_fileno (this ->input ());
1308
1344
1309
1345
util::configure_pipe (&this ->g_hChildStd_OUT_Rd , &this ->g_hChildStd_OUT_Wr , &this ->g_hChildStd_OUT_Rd );
1310
1346
this ->output (util::file_from_handle (this ->g_hChildStd_OUT_Rd , " r" ));
1311
- this ->read_from_child_ = _fileno (this ->output ());
1347
+ this ->read_from_child_ = subprocess_fileno (this ->output ());
1312
1348
1313
1349
util::configure_pipe (&this ->g_hChildStd_ERR_Rd , &this ->g_hChildStd_ERR_Wr , &this ->g_hChildStd_ERR_Rd );
1314
1350
this ->error (util::file_from_handle (this ->g_hChildStd_ERR_Rd , " r" ));
1315
- this ->err_read_ = _fileno (this ->error ());
1351
+ this ->err_read_ = subprocess_fileno (this ->error ());
1316
1352
#else
1317
1353
1318
1354
if (write_to_child_ != -1 ) input (fdopen (write_to_child_, " wb" ));
0 commit comments