From c4389103bdbe0e6eba53d5090a584c787fa9462b Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 8 Apr 2019 10:58:50 +0200 Subject: [PATCH 1/2] Fix Windows command escape for \" refs #4849 --- lib/base/utility.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index 331af3832..7b9162e97 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -1147,7 +1147,7 @@ String Utility::EscapeCreateProcessArg(const String& arg) result.Append(numBackslashes * 2, '\\'); break; } else if (*it == '"') { - result.Append(numBackslashes * 2, '\\'); + result.Append(numBackslashes * 2 + 1, '\\'); result.Append(1, *it); } else { result.Append(numBackslashes, '\\'); From 56095b29f4beab8f05721ea356e061400e7816b7 Mon Sep 17 00:00:00 2001 From: Julian Brost Date: Thu, 28 Jan 2021 16:25:12 +0100 Subject: [PATCH 2/2] Add tests for Utility::EscapeCreateProcessArg --- test/CMakeLists.txt | 1 + test/base-utility.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b973a4361..8649a4865 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -111,6 +111,7 @@ add_boost_test(base base_utility/comparepasswords_works base_utility/comparepasswords_issafe base_utility/validateutf8 + base_utility/EscapeCreateProcessArg base_value/scalar base_value/convert base_value/format diff --git a/test/base-utility.cpp b/test/base-utility.cpp index a73c32008..43fba3b30 100644 --- a/test/base-utility.cpp +++ b/test/base-utility.cpp @@ -4,6 +4,12 @@ #include #include +#ifdef _WIN32 +# include +# include +# include +#endif /* _WIN32 */ + using namespace icinga; BOOST_AUTO_TEST_SUITE(base_utility) @@ -58,4 +64,33 @@ BOOST_AUTO_TEST_CASE(validateutf8) BOOST_CHECK(Utility::ValidateUTF8("\xC3\xA4") == "\xC3\xA4"); } +BOOST_AUTO_TEST_CASE(EscapeCreateProcessArg) +{ +#ifdef _WIN32 + std::vector testdata = { + R"(foobar)", + R"(foo bar)", + R"(foo"bar)", + R"("foo bar")", + R"(" \" \\" \\\" \\\\")", + R"( !"#$$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~ " \" \\" \\\" \\\\")", + "'foo\nbar'", + }; + + for (const auto& t : testdata) { + // Prepend some fake exec name as the first argument is handled differently. + std::string escaped = "some.exe " + Utility::EscapeCreateProcessArg(t); + int argc; + std::shared_ptr argv(CommandLineToArgvW(CA2W(escaped.c_str()), &argc), LocalFree); + BOOST_CHECK_MESSAGE(argv != nullptr, "CommandLineToArgvW() should not return nullptr for " << t); + BOOST_CHECK_MESSAGE(argc == 2, "CommandLineToArgvW() should find 2 arguments for " << t); + if (argc >= 2) { + std::string unescaped = CW2A(argv.get()[1]); + BOOST_CHECK_MESSAGE(unescaped == t, + "CommandLineToArgvW() should return original value for " << t << " (got: " << unescaped << ")"); + } + } +#endif /* _WIN32 */ +} + BOOST_AUTO_TEST_SUITE_END()