buffer.push_back(0);
}
-bool GetFlattenedWindowsCommandString(Args args, std::string &command) {
+bool GetFlattenedWindowsCommandString(Args args, std::wstring &command) {
if (args.empty())
return false;
for (auto &entry : args.entries())
args_ref.push_back(entry.ref());
- command = llvm::sys::flattenWindowsCommandLine(args_ref);
+ llvm::ErrorOr<std::wstring> result =
+ llvm::sys::flattenWindowsCommandLine(args_ref);
+ if (result.getError())
+ return false;
+
+ command = *result;
return true;
}
} // namespace
error.Clear();
std::string executable;
- std::string commandLine;
std::vector<char> environment;
STARTUPINFO startupinfo = {};
PROCESS_INFORMATION pi = {};
env_block = environment.data();
executable = launch_info.GetExecutableFile().GetPath();
- GetFlattenedWindowsCommandString(launch_info.GetArguments(), commandLine);
+ std::wstring wcommandLine;
+ GetFlattenedWindowsCommandString(launch_info.GetArguments(), wcommandLine);
- std::wstring wexecutable, wcommandLine, wworkingDirectory;
+ std::wstring wexecutable, wworkingDirectory;
llvm::ConvertUTF8toWide(executable, wexecutable);
- llvm::ConvertUTF8toWide(commandLine, wcommandLine);
llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(),
wworkingDirectory);
// If the command line is empty, it's best to pass a null pointer to tell
// Windows wants a command line, not an array of args, to pass to the new
// process. We have to concatenate them all, while quoting the args that
// have embedded spaces (or are empty).
- std::string Command = flattenWindowsCommandLine(Args);
+ auto Result = flattenWindowsCommandLine(Args);
+ if (std::error_code ec = Result.getError()) {
+ SetLastError(ec.value());
+ MakeErrMsg(ErrMsg, std::string("Unable to convert command-line to UTF-16"));
+ return false;
+ }
+ std::wstring Command = *Result;
// The pointer to the environment block for the new process.
std::vector<wchar_t> EnvBlock;
return false;
}
- SmallVector<wchar_t, MAX_PATH> CommandUtf16;
- if (std::error_code ec = windows::UTF8ToUTF16(Command, CommandUtf16)) {
- SetLastError(ec.value());
- MakeErrMsg(ErrMsg,
- std::string("Unable to convert command-line to UTF-16"));
- return false;
- }
-
- BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0,
- TRUE, CREATE_UNICODE_ENVIRONMENT,
- EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si,
- &pi);
+ std::vector<wchar_t> CommandUtf16(Command.size() + 1, 0);
+ std::copy(Command.begin(), Command.end(), CommandUtf16.begin());
+ BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, TRUE,
+ CREATE_UNICODE_ENVIRONMENT,
+ EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si, &pi);
DWORD err = GetLastError();
// Regardless of whether the process got created or not, we are done with
}
namespace llvm {
-std::string sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) {
+ErrorOr<std::wstring> sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) {
std::string Command;
for (StringRef Arg : Args) {
if (argNeedsQuotes(Arg))
Command.push_back(' ');
}
- return Command;
+ SmallVector<wchar_t, MAX_PATH> CommandUtf16;
+ if (std::error_code ec = windows::UTF8ToUTF16(Command, CommandUtf16))
+ return ec;
+
+ return std::wstring(CommandUtf16.begin(), CommandUtf16.end());
}
ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program,
ArrayRef<StringRef> Args) {
- // The documented max length of the command line passed to CreateProcess.
- static const size_t MaxCommandStringLength = 32768;
+ // The documentation on CreateProcessW states that the size of the argument
+ // lpCommandLine must not be greater than 32767 characters, including the
+ // Unicode terminating null character. We use smaller value to reduce risk
+ // of getting invalid command line due to unaccounted factors.
+ static const size_t MaxCommandStringLength = 32000;
SmallVector<StringRef, 8> FullArgs;
FullArgs.push_back(Program);
FullArgs.append(Args.begin(), Args.end());
- std::string Result = flattenWindowsCommandLine(FullArgs);
- return (Result.size() + 1) <= MaxCommandStringLength;
+ auto Result = flattenWindowsCommandLine(FullArgs);
+ assert(!Result.getError());
+ return (Result->size() + 1) <= MaxCommandStringLength;
}
}
TEST(CommandLineTest, ArgumentLimit) {
std::string args(32 * 4096, 'a');
EXPECT_FALSE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args.data()));
+ std::string args2(256, 'a');
+ EXPECT_TRUE(llvm::sys::commandLineFitsWithinSystemLimits("cl", args2.data()));
+ if (Triple(sys::getProcessTriple()).isOSWindows()) {
+ // We use 32000 as a limit for command line length. Program name ('cl'),
+ // separating spaces and termination null character occupy 5 symbols.
+ std::string long_arg(32000 - 5, 'b');
+ EXPECT_TRUE(
+ llvm::sys::commandLineFitsWithinSystemLimits("cl", long_arg.data()));
+ long_arg += 'b';
+ EXPECT_FALSE(
+ llvm::sys::commandLineFitsWithinSystemLimits("cl", long_arg.data()));
+ }
}
TEST(CommandLineTest, ResponseFileWindows) {