From 778543b2f2ca7f5d1c4f0241b635bbb265d750dd Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 24 Apr 2025 06:44:22 +0100 Subject: [PATCH] Avoid leaking POSIX name aliases beyond `subprocess.hpp` (#112) The commit a32c0f3df4b6bcd1d2e93f19e8f380bb890cd507 introduced code to silence MSVC's "warning C4996: The POSIX name for this item is deprecated." However, it exhibits several issues: 1. The aliases may leak into code outside the `subprocess.hpp` header. 2. They are unnecessarily applied when using the MinGW-w64 toolchain. 3. The fix is incomplete: downstream projects still see C4996 warnings. 4. The implementation lacks documentation. This change addresses all of the above shortcomings. Co-authored-by: Luke Dashjr --- subprocess.hpp | 80 +++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/subprocess.hpp b/subprocess.hpp index 2638a31..b572e37 100755 --- a/subprocess.hpp +++ b/subprocess.hpp @@ -64,10 +64,6 @@ extern "C" { #include #include #include - - #define close _close - #define open _open - #define fileno _fileno #else #include #include @@ -77,6 +73,22 @@ extern "C" { #include } +// The Microsoft C++ compiler issues deprecation warnings +// for the standard POSIX function names. +// Its preferred implementations have a leading underscore. +// See: https://learn.microsoft.com/en-us/cpp/c-runtime-library/compatibility. +#if (defined _MSC_VER) + #define subprocess_close _close + #define subprocess_fileno _fileno + #define subprocess_open _open + #define subprocess_write _write +#else + #define subprocess_close close + #define subprocess_fileno fileno + #define subprocess_open open + #define subprocess_write write +#endif + /*! * Getting started with reading this source code. * The source is mainly divided into four parts: @@ -281,7 +293,7 @@ namespace util FILE *fp = _fdopen(os_fhandle, mode); if (fp == 0) { - _close(os_fhandle); + subprocess_close(os_fhandle); throw OSError("_fdopen", 0); } @@ -514,7 +526,7 @@ namespace util { size_t nwritten = 0; while (nwritten < length) { - int written = write(fd, buf + nwritten, length - nwritten); + int written = subprocess_write(fd, buf + nwritten, length - nwritten); if (written == -1) return -1; nwritten += written; } @@ -542,7 +554,7 @@ namespace util #ifdef __USING_WINDOWS__ return (int)fread(buf, 1, read_upto, fp); #else - int fd = fileno(fp); + int fd = subprocess_fileno(fp); int rbytes = 0; int eintr_cnter = 0; @@ -783,10 +795,10 @@ struct input explicit input(int fd): rd_ch_(fd) {} // FILE pointer. - explicit input (FILE* fp):input(fileno(fp)) { assert(fp); } + explicit input (FILE* fp):input(subprocess_fileno(fp)) { assert(fp); } explicit input(const char* filename) { - int fd = open(filename, O_RDONLY); + int fd = subprocess_open(filename, O_RDONLY); if (fd == -1) throw OSError("File not found: ", errno); rd_ch_ = fd; } @@ -816,10 +828,10 @@ struct output { explicit output(int fd): wr_ch_(fd) {} - explicit output (FILE* fp):output(fileno(fp)) { assert(fp); } + explicit output (FILE* fp):output(subprocess_fileno(fp)) { assert(fp); } explicit output(const char* filename) { - int fd = open(filename, O_APPEND | O_CREAT | O_RDWR, 0640); + int fd = subprocess_open(filename, O_APPEND | O_CREAT | O_RDWR, 0640); if (fd == -1) throw OSError("File not found: ", errno); wr_ch_ = fd; } @@ -847,10 +859,10 @@ struct error { explicit error(int fd): wr_ch_(fd) {} - explicit error(FILE* fp):error(fileno(fp)) { assert(fp); } + explicit error(FILE* fp):error(subprocess_fileno(fp)) { assert(fp); } explicit error(const char* filename) { - int fd = open(filename, O_APPEND | O_CREAT | O_RDWR, 0640); + int fd = subprocess_open(filename, O_APPEND | O_CREAT | O_RDWR, 0640); if (fd == -1) throw OSError("File not found: ", errno); wr_ch_ = fd; } @@ -1105,28 +1117,28 @@ public: void cleanup_fds() { if (write_to_child_ != -1 && read_from_parent_ != -1) { - close(write_to_child_); + subprocess_close(write_to_child_); } if (write_to_parent_ != -1 && read_from_child_ != -1) { - close(read_from_child_); + subprocess_close(read_from_child_); } if (err_write_ != -1 && err_read_ != -1) { - close(err_read_); + subprocess_close(err_read_); } } void close_parent_fds() { - if (write_to_child_ != -1) close(write_to_child_); - if (read_from_child_ != -1) close(read_from_child_); - if (err_read_ != -1) close(err_read_); + if (write_to_child_ != -1) subprocess_close(write_to_child_); + if (read_from_child_ != -1) subprocess_close(read_from_child_); + if (err_read_ != -1) subprocess_close(err_read_); } void close_child_fds() { - if (write_to_parent_ != -1) close(write_to_parent_); - if (read_from_parent_ != -1) close(read_from_parent_); - if (err_write_ != -1) close(err_write_); + if (write_to_parent_ != -1) subprocess_close(write_to_parent_); + if (read_from_parent_ != -1) subprocess_close(read_from_parent_); + if (err_write_ != -1) subprocess_close(err_write_); } FILE* input() { return input_.get(); } @@ -1613,8 +1625,8 @@ inline void Popen::execute_process() noexcept(false) child_pid_ = fork(); if (child_pid_ < 0) { - close(err_rd_pipe); - close(err_wr_pipe); + subprocess_close(err_rd_pipe); + subprocess_close(err_wr_pipe); throw OSError("fork failed", errno); } @@ -1626,14 +1638,14 @@ inline void Popen::execute_process() noexcept(false) stream_.close_parent_fds(); //Close the read end of the error pipe - close(err_rd_pipe); + subprocess_close(err_rd_pipe); detail::Child chld(this, err_wr_pipe); chld.execute_child(); } else { - close (err_wr_pipe);// close child side of pipe, else get stuck in read below + subprocess_close(err_wr_pipe);// close child side of pipe, else get stuck in read below stream_.close_child_fds(); @@ -1642,7 +1654,7 @@ inline void Popen::execute_process() noexcept(false) FILE* err_fp = fdopen(err_rd_pipe, "r"); if (!err_fp) { - close(err_rd_pipe); + subprocess_close(err_rd_pipe); throw OSError("fdopen failed", errno); } int read_bytes = util::read_atmost_n(err_fp, err_buf, SP_MAX_ERR_BUF_SIZ); @@ -1765,13 +1777,13 @@ namespace detail { // Close the duped descriptors if (stream.read_from_parent_ != -1 && stream.read_from_parent_ > 2) - close(stream.read_from_parent_); + subprocess_close(stream.read_from_parent_); if (stream.write_to_parent_ != -1 && stream.write_to_parent_ > 2) - close(stream.write_to_parent_); + subprocess_close(stream.write_to_parent_); if (stream.err_write_ != -1 && stream.err_write_ > 2) - close(stream.err_write_); + subprocess_close(stream.err_write_); // Close all the inherited fd's except the error write pipe if (parent_->close_fds_) { @@ -1780,7 +1792,7 @@ namespace detail { for (int i = 3; i < max_fd; i++) { if (i == err_wr_pipe_) continue; - close(i); + subprocess_close(i); } } @@ -1831,15 +1843,15 @@ namespace detail { #ifdef __USING_WINDOWS__ util::configure_pipe(&this->g_hChildStd_IN_Rd, &this->g_hChildStd_IN_Wr, &this->g_hChildStd_IN_Wr); this->input(util::file_from_handle(this->g_hChildStd_IN_Wr, "w")); - this->write_to_child_ = _fileno(this->input()); + this->write_to_child_ = subprocess_fileno(this->input()); util::configure_pipe(&this->g_hChildStd_OUT_Rd, &this->g_hChildStd_OUT_Wr, &this->g_hChildStd_OUT_Rd); this->output(util::file_from_handle(this->g_hChildStd_OUT_Rd, "r")); - this->read_from_child_ = _fileno(this->output()); + this->read_from_child_ = subprocess_fileno(this->output()); util::configure_pipe(&this->g_hChildStd_ERR_Rd, &this->g_hChildStd_ERR_Wr, &this->g_hChildStd_ERR_Rd); this->error(util::file_from_handle(this->g_hChildStd_ERR_Rd, "r")); - this->err_read_ = _fileno(this->error()); + this->err_read_ = subprocess_fileno(this->error()); #else if (write_to_child_ != -1) input(fdopen(write_to_child_, "wb"));