Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/boost/process/v2/detail/utf8.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,14 @@ std::basic_string<CharOut, Traits, Allocator> conv_string(
if (ec)
detail::throw_error(ec, "size_as_utf8");


std::basic_string<CharOut, Traits, Allocator> res(allocator);
res.resize(req_size);

if (req_size == 0)
return res;


auto res_size = convert_to_utf8(data, size, &res.front(), req_size, ec);
if (ec)
detail::throw_error(ec, "convert_to_utf8");
Expand All @@ -70,6 +75,9 @@ std::basic_string<CharOut, Traits, Allocator> conv_string(
std::basic_string<CharOut, Traits, Allocator> res(allocator);
res.resize(req_size);

if (req_size == 0)
return res;

auto res_size = convert_to_wide(data, size, &res.front(), req_size, ec);
if (ec)
detail::throw_error(ec, "convert_to_wide");
Expand Down
9 changes: 5 additions & 4 deletions include/boost/process/v2/windows/default_launcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,6 @@ struct default_launcher
BOOST_PROCESS_V2_DECL static
std::size_t escape_argv_string(wchar_t * itr, std::size_t max_size,
basic_string_view<wchar_t> ws);




Expand Down Expand Up @@ -395,6 +394,7 @@ struct default_launcher
{
return detail::conv_string<wchar_t>(arg.data(), arg.size());
});

return build_command_line_impl(pt, argw, L"");
}

Expand All @@ -406,10 +406,11 @@ struct default_launcher
{
std::wstring buffer;
buffer.resize(escaped_argv_length(pt.native()));
escape_argv_string(&buffer.front(), buffer.size(), pt.native());

if (!buffer.empty())
escape_argv_string(&buffer.front(), buffer.size(), pt.native());
return buffer;
}

return build_command_line_impl(pt, args, *std::begin(args));
}

Expand Down Expand Up @@ -438,4 +439,4 @@ BOOST_PROCESS_V2_END_NAMESPACE



#endif //BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP
#endif //BOOST_PROCESS_V2_WINDOWS_DEFAULT_LAUNCHER_HPP
81 changes: 52 additions & 29 deletions src/windows/default_launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,54 +24,72 @@ namespace windows
if (ws.empty())
return 2u; // just quotes

constexpr static auto space = L' ';
constexpr static auto quote = L'"';
const auto needs_quotes = ws.find_first_of(L" \t") != basic_string_view<wchar_t>::npos;

const auto has_space = ws.find(space) != basic_string_view<wchar_t>::npos;
const auto quoted = (ws.front() == quote) && (ws.back() == quote);
const auto needs_escape = has_space && !quoted ;

if (!needs_escape)
return ws.size();
else
return ws.size() + std::count(ws.begin(), ws.end(), quote) + 2u;
std::size_t needed_escapes = 0u;
for (auto itr = ws.begin(); itr != ws.end(); itr ++)
{
if (*itr == quote)
needed_escapes++;
else if (*itr == L'\\')
{
auto nx = std::next(itr);
if (nx != ws.end() && *nx == L'"')
needed_escapes ++;
else if (nx == ws.end())
needed_escapes ++;
}
}

return ws.size() + needed_escapes + (needs_quotes ? 2u : 0u);
}


std::size_t default_launcher::escape_argv_string(wchar_t * itr, std::size_t max_size,
basic_string_view<wchar_t> ws)
{
const auto sz = escaped_argv_length(ws);
constexpr static auto quote = L'"';
const auto needs_quotes = ws.find_first_of(L" \t") != basic_string_view<wchar_t>::npos;
const auto needed_escapes = std::count(ws.begin(), ws.end(), quote);

const auto sz = ws.size() + needed_escapes + (needs_quotes ? 2u : 0u);

if (sz > max_size)
return 0u;

if (ws.empty())
{
itr[0] = L'"';
itr[1] = L'"';
itr[0] = quote;
itr[1] = quote;
return 2u;
}

const auto has_space = ws.find(L' ') != basic_string_view<wchar_t>::npos;
const auto quoted = (ws.front() == L'"') && (ws.back() == L'"');
const auto needs_escape = has_space && !quoted;

if (!needs_escape)
return std::copy(ws.begin(), ws.end(), itr) - itr;

if (sz < (2u + ws.size()))
return 0u;

const auto end = itr + sz;
const auto begin = itr;
*(itr ++) = L'"';
for (auto wc : ws)
if (needs_quotes)
*(itr++) = quote;

for (auto it = ws.begin(); it != ws.end(); it ++)
{
if (wc == L'"')
if (*it == quote) // makes it \"
*(itr++) = L'\\';
*(itr++) = wc;

if (*it == L'\\') // \" needs to become \\\"
{
auto nx = std::next(it);
if (nx != ws.end() && *nx == L'"')
*(itr++) = L'\\';
else if (nx == ws.end())
*(itr++) = L'\\';

}

*(itr++) = *it;
}

*(itr ++) = L'"';
if (needs_quotes)
*(itr++) = quote;
return itr - begin;
}

Expand Down Expand Up @@ -108,13 +126,18 @@ namespace windows
auto tl = get_thread_attribute_list(ec);
if (ec)
return;

auto itr = std::unique(inherited_handles.begin(), inherited_handles.end());
auto size = std::distance(inherited_handles.begin(), itr);

if (!::UpdateProcThreadAttribute(
tl, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
inherited_handles.data(), inherited_handles.size() * sizeof(HANDLE), nullptr, nullptr))
inherited_handles.data(), size * sizeof(HANDLE), nullptr, nullptr))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec);
}

}
BOOST_PROCESS_V2_END_NAMESPACE

#endif
#endif

85 changes: 83 additions & 2 deletions test/v2/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,11 @@ BOOST_AUTO_TEST_CASE(print_args_spec_out)
asio::writable_pipe wp{ctx};
asio::connect_pipe(rp, wp);


bpv::process proc(ctx, pth, {"print-args", "&foo", "&", "|bar", "\"", "#foobar"}, bpv::process_stdio{/*in*/{},/*out*/wp, /*err*/ nullptr});
fprintf(stderr, "print_args_spec_out\n");

bpv::process proc(ctx, pth, {"print-args", "&foo", "&", "", "\"\"", "\\\"", "|bar", "\"", "#foobar"},
bpv::process_stdio{/*in*/{},/*out*/wp, /*err*/ nullptr});
BOOST_CHECK(proc.running());

wp.close();
asio::streambuf st;
Expand Down Expand Up @@ -288,6 +291,18 @@ BOOST_AUTO_TEST_CASE(print_args_spec_out)
trim_end(line);
BOOST_CHECK_EQUAL("&", line);

BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("", line);

BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("\"\"", line);

BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("\\\"", line);

BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("|bar", line);
Expand All @@ -296,6 +311,7 @@ BOOST_AUTO_TEST_CASE(print_args_spec_out)
trim_end(line);
BOOST_CHECK_EQUAL("\"", line);


BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("#foobar", line);
Expand Down Expand Up @@ -852,5 +868,70 @@ BOOST_AUTO_TEST_CASE(async_terminate_code)
#endif


BOOST_AUTO_TEST_CASE(print_args_combined)
{
using boost::unit_test::framework::master_test_suite;
const auto pth = master_test_suite().argv[1];

asio::io_context ctx;

asio::readable_pipe rp{ctx};
asio::writable_pipe wp{ctx};
asio::connect_pipe(rp, wp);

bpv::process proc(ctx, pth, {"print-args", "bar", "foo"}, bpv::process_stdio{/*in*/{}, /*.out= */ wp, /* .err=*/ wp});
wp.close();

asio::streambuf st;
std::istream is{&st};
bpv::error_code ec;

auto sz = asio::read(rp, st, ec);
while (ec == asio::error::interrupted)
sz += asio::read(rp, st, ec);

BOOST_CHECK_NE(sz , 0u);
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());

std::string line;
BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL(pth, line );

BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL(pth, line );


BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("print-args", line);

BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("print-args", line);


BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("bar", line);

BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("bar", line);

BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("foo", line);

BOOST_CHECK(std::getline(is, line));
trim_end(line);
BOOST_CHECK_EQUAL("foo", line);


proc.wait();
BOOST_CHECK_EQUAL(proc.exit_code(), 0);
}

BOOST_AUTO_TEST_SUITE_END();

Loading