fix(launch): Fix several launch failure conditions (exceptions thrown in child.wait, and boost::split_unix) (#4390)

This commit is contained in:
Martijn Courteaux 2025-11-12 16:07:15 +01:00 committed by GitHub
commit 852dee0a68
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 26 additions and 5 deletions

View file

@ -40,6 +40,8 @@ using namespace std::literals;
namespace nvhttp { namespace nvhttp {
static constexpr std::string_view EMPTY_PROPERTY_TREE_ERROR_MSG = "Property tree is empty. Probably, control flow got interrupted by an unexpected C++ exception. This is a bug in Sunshine. Moonlight-qt will report Malformed XML (missing root element)."sv;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace pt = boost::property_tree; namespace pt = boost::property_tree;
@ -816,6 +818,10 @@ namespace nvhttp {
auto g = util::fail_guard([&]() { auto g = util::fail_guard([&]() {
std::ostringstream data; std::ostringstream data;
if (tree.empty()) {
BOOST_LOG(error) << EMPTY_PROPERTY_TREE_ERROR_MSG;
}
pt::write_xml(data, tree); pt::write_xml(data, tree);
response->write(data.str()); response->write(data.str());
response->close_connection_after_response = true; response->close_connection_after_response = true;
@ -922,6 +928,10 @@ namespace nvhttp {
auto g = util::fail_guard([&]() { auto g = util::fail_guard([&]() {
std::ostringstream data; std::ostringstream data;
if (tree.empty()) {
BOOST_LOG(error) << EMPTY_PROPERTY_TREE_ERROR_MSG;
}
pt::write_xml(data, tree); pt::write_xml(data, tree);
response->write(data.str()); response->write(data.str());
response->close_connection_after_response = true; response->close_connection_after_response = true;

View file

@ -17,6 +17,7 @@
#include <boost/program_options/parsers.hpp> #include <boost/program_options/parsers.hpp>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/token_functions.hpp>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/sha.h> #include <openssl/sha.h>
@ -97,11 +98,17 @@ namespace proc {
boost::filesystem::path find_working_directory(const std::string &cmd, boost::process::v1::environment &env) { boost::filesystem::path find_working_directory(const std::string &cmd, boost::process::v1::environment &env) {
// Parse the raw command string into parts to get the actual command portion // Parse the raw command string into parts to get the actual command portion
std::vector<std::string> parts;
try {
#ifdef _WIN32 #ifdef _WIN32
auto parts = boost::program_options::split_winmain(cmd); parts = boost::program_options::split_winmain(cmd);
#else #else
auto parts = boost::program_options::split_unix(cmd); parts = boost::program_options::split_unix(cmd);
#endif #endif
} catch (boost::escaped_list_error &err) {
BOOST_LOG(error) << "Boost failed to parse command ["sv << cmd << "] because " << err.what();
return boost::filesystem::path();
}
if (parts.empty()) { if (parts.empty()) {
BOOST_LOG(error) << "Unable to parse command: "sv << cmd; BOOST_LOG(error) << "Unable to parse command: "sv << cmd;
return boost::filesystem::path(); return boost::filesystem::path();
@ -217,10 +224,14 @@ namespace proc {
} }
} }
child.wait(); child.wait(ec);
if (ec) {
BOOST_LOG(error) << '[' << cmd.do_cmd << "] wait failed with error code ["sv << ec << ']';
return -1;
}
auto ret = child.exit_code(); auto ret = child.exit_code();
if (ret != 0 && ec != std::errc::permission_denied) { if (ret != 0) {
BOOST_LOG(error) << '[' << cmd.do_cmd << "] failed with code ["sv << ret << ']'; BOOST_LOG(error) << '[' << cmd.do_cmd << "] exited with code ["sv << ret << ']';
return -1; return -1;
} }
} }