Merge 29868 via hww_windows-28

This commit is contained in:
Luke Dashjr 2025-03-05 03:27:08 +00:00
commit 301886f3d0
4 changed files with 66 additions and 33 deletions

View File

@ -110,7 +110,7 @@ fi
ccache --zero-stats ccache --zero-stats
PRINT_CCACHE_STATISTICS="ccache --version | head -n 1 && ccache --show-stats" PRINT_CCACHE_STATISTICS="ccache --version | head -n 1 && ccache --show-stats"
BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-external-signer --prefix=$BASE_OUTDIR" BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --prefix=$BASE_OUTDIR"
if [ -n "$CONFIG_SHELL" ]; then if [ -n "$CONFIG_SHELL" ]; then
"$CONFIG_SHELL" -c "./autogen.sh" "$CONFIG_SHELL" -c "./autogen.sh"

View File

@ -1386,7 +1386,7 @@ fi
case $host in case $host in
dnl Re-enable it after enabling Windows support in cpp-subprocess. dnl Re-enable it after enabling Windows support in cpp-subprocess.
*mingw*) *mingw*)
use_external_signer="no" true
;; ;;
esac esac
if test "$use_external_signer" = "yes"; then if test "$use_external_signer" = "yes"; then

View File

@ -32,7 +32,11 @@ BOOST_AUTO_TEST_CASE(run_command)
BOOST_CHECK(result.isNull()); BOOST_CHECK(result.isNull());
} }
{ {
#ifdef WIN32
const UniValue result = RunCommandParseJSON("cmd.exe /c echo {\"success\": true}");
#else
const UniValue result = RunCommandParseJSON("echo {\"success\": true}"); const UniValue result = RunCommandParseJSON("echo {\"success\": true}");
#endif
BOOST_CHECK(result.isObject()); BOOST_CHECK(result.isObject());
const UniValue& success = result.find_value("success"); const UniValue& success = result.find_value("success");
BOOST_CHECK(!success.isNull()); BOOST_CHECK(!success.isNull());
@ -40,12 +44,20 @@ BOOST_AUTO_TEST_CASE(run_command)
} }
{ {
// An invalid command is handled by cpp-subprocess // An invalid command is handled by cpp-subprocess
#ifdef WIN32
const std::string expected{"CreateProcess failed: "};
#else
const std::string expected{"execve failed: "}; const std::string expected{"execve failed: "};
#endif
BOOST_CHECK_EXCEPTION(RunCommandParseJSON("invalid_command"), subprocess::CalledProcessError, HasReason(expected)); BOOST_CHECK_EXCEPTION(RunCommandParseJSON("invalid_command"), subprocess::CalledProcessError, HasReason(expected));
} }
{ {
// Return non-zero exit code, no output to stderr // Return non-zero exit code, no output to stderr
#ifdef WIN32
const std::string command{"cmd.exe /c exit 1"};
#else
const std::string command{"false"}; const std::string command{"false"};
#endif
BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) { BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) {
const std::string what{e.what()}; const std::string what{e.what()};
BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned 1: \n", command)) != std::string::npos); BOOST_CHECK(what.find(strprintf("RunCommandParseJSON error: process(%s) returned 1: \n", command)) != std::string::npos);
@ -54,7 +66,11 @@ BOOST_AUTO_TEST_CASE(run_command)
} }
{ {
// Return non-zero exit code, with error message for stderr // Return non-zero exit code, with error message for stderr
#ifdef WIN32
const std::string command{"cmd.exe /c \"echo err 1>&2 && exit 1\""};
#else
const std::string command{"sh -c 'echo err 1>&2 && false'"}; const std::string command{"sh -c 'echo err 1>&2 && false'"};
#endif
const std::string expected{"err"}; const std::string expected{"err"};
BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) { BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, [&](const std::runtime_error& e) {
const std::string what(e.what()); const std::string what(e.what());
@ -65,9 +81,14 @@ BOOST_AUTO_TEST_CASE(run_command)
} }
{ {
// Unable to parse JSON // Unable to parse JSON
#ifdef WIN32
const std::string command{"cmd.exe /c echo {"};
#else
const std::string command{"echo {"}; const std::string command{"echo {"};
#endif
BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, HasReason("Unable to parse JSON: {")); BOOST_CHECK_EXCEPTION(RunCommandParseJSON(command), std::runtime_error, HasReason("Unable to parse JSON: {"));
} }
#ifndef WIN32
// Test std::in // Test std::in
{ {
const UniValue result = RunCommandParseJSON("cat", "{\"success\": true}"); const UniValue result = RunCommandParseJSON("cat", "{\"success\": true}");
@ -76,6 +97,7 @@ BOOST_AUTO_TEST_CASE(run_command)
BOOST_CHECK(!success.isNull()); BOOST_CHECK(!success.isNull());
BOOST_CHECK_EQUAL(success.get_bool(), true); BOOST_CHECK_EQUAL(success.get_bool(), true);
} }
#endif
} }
#endif // ENABLE_EXTERNAL_SIGNER #endif // ENABLE_EXTERNAL_SIGNER

View File

@ -57,7 +57,7 @@ Documentation for C++ subprocessing library.
#include <string> #include <string>
#include <vector> #include <vector>
#if (defined _MSC_VER) || (defined __MINGW32__) #ifdef WIN32
#define __USING_WINDOWS__ #define __USING_WINDOWS__
#endif #endif
@ -67,16 +67,20 @@ Documentation for C++ subprocessing library.
extern "C" { extern "C" {
#ifdef __USING_WINDOWS__ #ifdef __USING_WINDOWS__
#include <Windows.h> #include <windows.h>
#include <io.h> #include <io.h>
#include <cwchar> #include <cwchar>
#define close _close #define subprocess_close _close
#define open _open #define subprocess_open _open
#define fileno _fileno #define subprocess_fileno _fileno
#else #else
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#define subprocess_close close
#define subprocess_open open
#define subprocess_fileno fileno
#endif #endif
#include <csignal> #include <csignal>
#include <fcntl.h> #include <fcntl.h>
@ -171,7 +175,7 @@ namespace util
// //
if (force == false && argument.empty() == false && if (force == false && argument.empty() == false &&
argument.find_first_of(L" \t\n\v\"") == argument.npos) { argument.find_first_of(L" \t\n\v") == argument.npos) {
command_line.append(argument); command_line.append(argument);
} }
else { else {
@ -413,7 +417,7 @@ namespace util
#ifdef __USING_WINDOWS__ #ifdef __USING_WINDOWS__
return (int)fread(buf, 1, read_upto, fp); return (int)fread(buf, 1, read_upto, fp);
#else #else
int fd = fileno(fp); int fd = subprocess_fileno(fp);
int rbytes = 0; int rbytes = 0;
int eintr_cnter = 0; int eintr_cnter = 0;
@ -589,10 +593,10 @@ struct input
explicit input(int fd): rd_ch_(fd) {} explicit input(int fd): rd_ch_(fd) {}
// FILE pointer. // 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) { 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); if (fd == -1) throw OSError("File not found: ", errno);
rd_ch_ = fd; rd_ch_ = fd;
} }
@ -622,10 +626,10 @@ struct output
{ {
explicit output(int fd): wr_ch_(fd) {} 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) { 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); if (fd == -1) throw OSError("File not found: ", errno);
wr_ch_ = fd; wr_ch_ = fd;
} }
@ -653,10 +657,10 @@ struct error
{ {
explicit error(int fd): wr_ch_(fd) {} 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) { 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); if (fd == -1) throw OSError("File not found: ", errno);
wr_ch_ = fd; wr_ch_ = fd;
} }
@ -820,28 +824,28 @@ public:
void cleanup_fds() void cleanup_fds()
{ {
if (write_to_child_ != -1 && read_from_parent_ != -1) { 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) { 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) { if (err_write_ != -1 && err_read_ != -1) {
close(err_read_); subprocess_close(err_read_);
} }
} }
void close_parent_fds() void close_parent_fds()
{ {
if (write_to_child_ != -1) close(write_to_child_); if (write_to_child_ != -1) subprocess_close(write_to_child_);
if (read_from_child_ != -1) close(read_from_child_); if (read_from_child_ != -1) subprocess_close(read_from_child_);
if (err_read_ != -1) close(err_read_); if (err_read_ != -1) subprocess_close(err_read_);
} }
void close_child_fds() void close_child_fds()
{ {
if (write_to_parent_ != -1) close(write_to_parent_); if (write_to_parent_ != -1) subprocess_close(write_to_parent_);
if (read_from_parent_ != -1) close(read_from_parent_); if (read_from_parent_ != -1) subprocess_close(read_from_parent_);
if (err_write_ != -1) close(err_write_); if (err_write_ != -1) subprocess_close(err_write_);
} }
FILE* input() { return input_.get(); } FILE* input() { return input_.get(); }
@ -1061,8 +1065,15 @@ inline int Popen::wait() noexcept(false)
{ {
#ifdef __USING_WINDOWS__ #ifdef __USING_WINDOWS__
int ret = WaitForSingleObject(process_handle_, INFINITE); int ret = WaitForSingleObject(process_handle_, INFINITE);
if (ret != WAIT_OBJECT_0) return -1;
return 0; DWORD dretcode_;
if (FALSE == GetExitCodeProcess(process_handle_, &dretcode_))
throw OSError("GetExitCodeProcess", 0);
CloseHandle(process_handle_);
return (int)dretcode_;
#else #else
int ret, status; int ret, status;
std::tie(ret, status) = util::wait_for_child_exit(child_pid_); std::tie(ret, status) = util::wait_for_child_exit(child_pid_);
@ -1175,8 +1186,8 @@ inline void Popen::execute_process() noexcept(false)
child_pid_ = fork(); child_pid_ = fork();
if (child_pid_ < 0) { if (child_pid_ < 0) {
close(err_rd_pipe); subprocess_close(err_rd_pipe);
close(err_wr_pipe); subprocess_close(err_wr_pipe);
throw OSError("fork failed", errno); throw OSError("fork failed", errno);
} }
@ -1186,14 +1197,14 @@ inline void Popen::execute_process() noexcept(false)
stream_.close_parent_fds(); stream_.close_parent_fds();
//Close the read end of the error pipe //Close the read end of the error pipe
close(err_rd_pipe); subprocess_close(err_rd_pipe);
detail::Child chld(this, err_wr_pipe); detail::Child chld(this, err_wr_pipe);
chld.execute_child(); chld.execute_child();
} }
else 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(); stream_.close_child_fds();
@ -1204,7 +1215,7 @@ inline void Popen::execute_process() noexcept(false)
fdopen(err_rd_pipe, "r"), fdopen(err_rd_pipe, "r"),
err_buf, err_buf,
SP_MAX_ERR_BUF_SIZ); SP_MAX_ERR_BUF_SIZ);
close(err_rd_pipe); subprocess_close(err_rd_pipe);
if (read_bytes || strlen(err_buf)) { if (read_bytes || strlen(err_buf)) {
// Call waitpid to reap the child process // Call waitpid to reap the child process
@ -1294,13 +1305,13 @@ namespace detail {
// Close the duped descriptors // Close the duped descriptors
if (stream.read_from_parent_ != -1 && stream.read_from_parent_ > 2) 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) 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) 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 // Close all the inherited fd's except the error write pipe
if (parent_->close_fds_) { if (parent_->close_fds_) {