From a2d2753aa8fe4f58b163f76d17d1c43f144146bc Mon Sep 17 00:00:00 2001 From: Klemens Morgenstern Date: Mon, 13 Jan 2025 09:31:48 +0800 Subject: [PATCH] zombie process fixes closes #445, #447 --- .../process/v2/posix/default_launcher.hpp | 44 +++---------------- .../v2/posix/fork_and_forget_launcher.hpp | 1 + .../process/v2/posix/pdfork_launcher.hpp | 1 + .../boost/process/v2/posix/vfork_launcher.hpp | 1 + .../process/v2/windows/default_launcher.hpp | 2 +- test/v2/process.cpp | 36 +++++++++++++++ 6 files changed, 46 insertions(+), 39 deletions(-) diff --git a/include/boost/process/v2/posix/default_launcher.hpp b/include/boost/process/v2/posix/default_launcher.hpp index 0ed0b9211..d17bda5e7 100644 --- a/include/boost/process/v2/posix/default_launcher.hpp +++ b/include/boost/process/v2/posix/default_launcher.hpp @@ -26,6 +26,8 @@ #endif #include +#include +#include #include @@ -96,7 +98,7 @@ template inline auto invoke_on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line), const error_code & ec, Init && init, derived && ) --> decltype(init.on_error(launcher, ec, executable, cmd_line, ec)) +-> decltype(init.on_error(launcher, executable, cmd_line, ec)) { init.on_error(launcher, executable, cmd_line, ec); } @@ -160,7 +162,7 @@ template inline auto invoke_on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line), const error_code & ec, Init && init, derived && ) --> decltype(init.on_fork_error(launcher, ec, executable, cmd_line, ec)) +-> decltype(init.on_fork_error(launcher, executable, cmd_line, ec)) { init.on_fork_error(launcher, executable, cmd_line, ec); } @@ -182,41 +184,6 @@ inline void on_fork_error(Launcher & launcher, const filesystem::path &executabl on_fork_error(launcher, executable, cmd_line, ec, inits...); } - - -template -inline void invoke_on_fork_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/, - const char * const * (&/*cmd_line*/), - Init && /*init*/, base && ) -{ - -} - -template -inline auto invoke_on_fork_success(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - Init && init, derived && ) --> decltype(init.on_fork_success(launcher, executable, cmd_line)) -{ - init.on_fork_success(launcher, executable, cmd_line); -} - -template -inline void on_fork_success(Launcher & /*launcher*/, const filesystem::path &/*executable*/, - const char * const * (&/*cmd_line*/)) -{ -} - -template -inline void on_fork_success(Launcher & launcher, const filesystem::path &executable, - const char * const * (&cmd_line), - Init1 && init1, Inits && ... inits) -{ - invoke_on_fork_success(launcher, executable, cmd_line, init1, derived{}); - on_fork_success(launcher, executable, cmd_line, inits...); -} - - template inline error_code invoke_on_exec_setup(Launcher & /*launcher*/, const filesystem::path &/*executable*/, const char * const * (&/*cmd_line*/), @@ -266,7 +233,7 @@ template inline auto invoke_on_exec_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line), const error_code & ec, Init && init, derived && ) --> decltype(init.on_exec_error(launcher, ec, executable, cmd_line, ec)) +-> decltype(init.on_exec_error(launcher, executable, cmd_line, ec)) { init.on_exec_error(launcher, executable, cmd_line, ec); } @@ -440,6 +407,7 @@ struct default_launcher if (ec) { detail::on_error(*this, executable, argv, ec, inits...); + do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR); return basic_process{exec}; } } diff --git a/include/boost/process/v2/posix/fork_and_forget_launcher.hpp b/include/boost/process/v2/posix/fork_and_forget_launcher.hpp index 91a622d3b..f86314dee 100644 --- a/include/boost/process/v2/posix/fork_and_forget_launcher.hpp +++ b/include/boost/process/v2/posix/fork_and_forget_launcher.hpp @@ -124,6 +124,7 @@ struct fork_and_forget_launcher : default_launcher if (ec) { detail::on_error(*this, executable, argv, ec, inits...); + do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR); return basic_process{exec}; } } diff --git a/include/boost/process/v2/posix/pdfork_launcher.hpp b/include/boost/process/v2/posix/pdfork_launcher.hpp index 16e5ca821..0a082f562 100644 --- a/include/boost/process/v2/posix/pdfork_launcher.hpp +++ b/include/boost/process/v2/posix/pdfork_launcher.hpp @@ -161,6 +161,7 @@ struct pdfork_launcher : default_launcher if (ec) { detail::on_error(*this, executable, argv, ec, inits...); + do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR); return basic_process{exec}; } } diff --git a/include/boost/process/v2/posix/vfork_launcher.hpp b/include/boost/process/v2/posix/vfork_launcher.hpp index cec0ca1eb..bb1b9f2ca 100644 --- a/include/boost/process/v2/posix/vfork_launcher.hpp +++ b/include/boost/process/v2/posix/vfork_launcher.hpp @@ -121,6 +121,7 @@ struct vfork_launcher : default_launcher if (ec) { detail::on_error(*this, executable, argv, ec, inits...); + do { ::waitpid(pid, nullptr, 0); } while (errno == EINTR); return basic_process{exec}; } diff --git a/include/boost/process/v2/windows/default_launcher.hpp b/include/boost/process/v2/windows/default_launcher.hpp index b41f87c49..d0ca19b4d 100644 --- a/include/boost/process/v2/windows/default_launcher.hpp +++ b/include/boost/process/v2/windows/default_launcher.hpp @@ -97,7 +97,7 @@ inline void invoke_on_error(Launcher & /*launcher*/, const filesystem::path &/*e template inline auto invoke_on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line, const error_code & ec, Init && init, derived && ) --> decltype(init.on_error(launcher, ec, executable, cmd_line, ec)) +-> decltype(init.on_error(launcher, executable, cmd_line, ec)) { init.on_error(launcher, executable, cmd_line, ec); } diff --git a/test/v2/process.cpp b/test/v2/process.cpp index 694afea2d..276625ec2 100644 --- a/test/v2/process.cpp +++ b/test/v2/process.cpp @@ -734,6 +734,42 @@ BOOST_AUTO_TEST_CASE(async_cancel_wait) ctx.run(); } +#if defined(BOOST_POSIX_API) + +struct capture_pid +{ + pid_t &pid; + template + void on_error(Launcher &launcher, const bpv::filesystem::path& executable, + const char * const * (&/*cmd_line*/), const bpv::error_code & ec) + { + BOOST_REQUIRE(!bpv::filesystem::exists(executable)); + this->pid = launcher.pid; + } +}; + +BOOST_AUTO_TEST_CASE(no_zombie) +{ + asio::io_context ctx; + using boost::unit_test::framework::master_test_suite; + const auto pth = bpv::filesystem::absolute(master_test_suite().argv[1]); + + pid_t res{-1}; + + + boost::system::error_code ec; + bpv::default_process_launcher()(ctx, ec, "/send/more/cops", std::vector{}, capture_pid{res}); + BOOST_CHECK(ec == boost::system::errc::no_such_file_or_directory); + + BOOST_REQUIRE(res != -1); + BOOST_CHECK(res != 0); + auto r = waitpid(res, nullptr, 0); + BOOST_CHECK(r < 0); + BOOST_CHECK_EQUAL(errno, ECHILD); +} + +#endif + BOOST_AUTO_TEST_SUITE_END();