Program.inc revision 0b675d88309bdcbb387bbee907c4ef9d98e412a2
13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// 23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// 33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// The LLVM Compiler Infrastructure 43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// 53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// This file is distributed under the University of Illinois Open Source 63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// License. See LICENSE.TXT for details. 73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// 83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//===----------------------------------------------------------------------===// 93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// 103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// This file provides the Win32 specific implementation of the Program class. 113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// 123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//===----------------------------------------------------------------------===// 133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "Windows.h" 153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <cstdio> 163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <fcntl.h> 173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <io.h> 183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include <malloc.h> 193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//===----------------------------------------------------------------------===// 213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//=== WARNING: Implementation here must contain only Win32 specific code 223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//=== and must not be UNIX code 233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//===----------------------------------------------------------------------===// 243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 253c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace { 263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry struct Win32ProcessInfo { 273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry HANDLE hProcess; 283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DWORD dwProcessId; 293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry }; 303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 323c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace llvm { 333c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing namespace sys; 343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 353c827367444ee418f129b2c238299f49d3264554Jarkko PoyryProgram::Program() : Data_(0) {} 363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 373c827367444ee418f129b2c238299f49d3264554Jarkko PoyryProgram::~Program() { 383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (Data_) { 393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); 403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry CloseHandle(wpi->hProcess); 413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry delete wpi; 423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Data_ = 0; 433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// This function just uses the PATH environment variable to find the program. 473c827367444ee418f129b2c238299f49d3264554Jarkko PoyryPath 483c827367444ee418f129b2c238299f49d3264554Jarkko PoyryProgram::FindProgramByName(const std::string& progName) { 493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Check some degenerate cases 513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (progName.length() == 0) // no program 523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return Path(); 533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Path temp; 543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!temp.set(progName)) // invalid name 553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return Path(); 563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Return paths with slashes verbatim. 573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (progName.find('\\') != std::string::npos || 583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry progName.find('/') != std::string::npos) 593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return temp; 603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // At this point, the file name is valid and does not contain slashes. 623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Let Windows search for it. 633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry char buffer[MAX_PATH]; 643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry char *dummy = NULL; 653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, 663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry buffer, &dummy); 673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // See if it wasn't found. 693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (len == 0) 703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return Path(); 713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // See if we got the entire path. 733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (len < MAX_PATH) 743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return Path(buffer); 753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Buffer was too small; grow and retry. 773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry while (true) { 783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry char *b = reinterpret_cast<char *>(_alloca(len+1)); 793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); 803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // It is unlikely the search failed, but it's always possible some file 823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // was added or removed since the last search, so be paranoid... 833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (len2 == 0) 843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return Path(); 853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry else if (len2 <= len) 863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return Path(b); 873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry len = len2; 893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 90c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry} 91c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry 923c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { 93c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry HANDLE h; 943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (path == 0) { 95c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), 96c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry GetCurrentProcess(), &h, 973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 0, TRUE, DUPLICATE_SAME_ACCESS); 98c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry return h; 99c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry } 100c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry 101c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry const char *fname; 1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (path->isEmpty()) 103c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry fname = "NUL"; 104c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry else 105c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry fname = path->c_str(); 106c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry 1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry SECURITY_ATTRIBUTES sa; 108c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry sa.nLength = sizeof(sa); 109c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry sa.lpSecurityDescriptor = 0; 110c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry sa.bInheritHandle = TRUE; 111c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry 112c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, 113c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, 1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry FILE_ATTRIBUTE_NORMAL, NULL); 1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (h == INVALID_HANDLE_VALUE) { 116c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + 117c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry (fd ? "input: " : "output: ")); 1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return h; 1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 123c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling 124c423ce6164cdd88c8c3e47bec4ec34476743042aJarkko Pöyry/// CreateProcess. 1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic bool ArgNeedsQuotes(const char *Str) { 1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0; 1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/// CountPrecedingBackslashes - Returns the number of backslashes preceding Cur 1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/// in the C string Start. 1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic unsigned int CountPrecedingBackslashes(const char *Start, 1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const char *Cur) { 1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry unsigned int Count = 0; 134 --Cur; 135 while (Cur >= Start && *Cur == '\\') { 136 ++Count; 137 --Cur; 138 } 139 return Count; 140} 141 142/// EscapePrecedingEscapes - Append a backslash to Dst for every backslash 143/// preceding Cur in the Start string. Assumes Dst has enough space. 144static char *EscapePrecedingEscapes(char *Dst, const char *Start, 145 const char *Cur) { 146 unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Cur); 147 while (PrecedingEscapes > 0) { 148 *Dst++ = '\\'; 149 --PrecedingEscapes; 150 } 151 return Dst; 152} 153 154/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling 155/// CreateProcess and returns length of quoted arg with escaped quotes 156static unsigned int ArgLenWithQuotes(const char *Str) { 157 const char *Start = Str; 158 unsigned int len = ArgNeedsQuotes(Str) ? 2 : 0; 159 160 while (*Str != '\0') { 161 if (*Str == '\"') { 162 // We need to add a backslash, but ensure that it isn't escaped. 163 unsigned PrecedingEscapes = CountPrecedingBackslashes(Start, Str); 164 len += PrecedingEscapes + 1; 165 } 166 // Note that we *don't* need to escape runs of backslashes that don't 167 // precede a double quote! See MSDN: 168 // http://msdn.microsoft.com/en-us/library/17w5ykft%28v=vs.85%29.aspx 169 170 ++len; 171 ++Str; 172 } 173 174 return len; 175} 176 177 178bool 179Program::Execute(const Path& path, 180 const char** args, 181 const char** envp, 182 const Path** redirects, 183 unsigned memoryLimit, 184 std::string* ErrMsg) { 185 if (Data_) { 186 Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); 187 CloseHandle(wpi->hProcess); 188 delete wpi; 189 Data_ = 0; 190 } 191 192 if (!path.canExecute()) { 193 if (ErrMsg) 194 *ErrMsg = "program not executable"; 195 return false; 196 } 197 198 // Windows wants a command line, not an array of args, to pass to the new 199 // process. We have to concatenate them all, while quoting the args that 200 // have embedded spaces (or are empty). 201 202 // First, determine the length of the command line. 203 unsigned len = 0; 204 for (unsigned i = 0; args[i]; i++) { 205 len += ArgLenWithQuotes(args[i]) + 1; 206 } 207 208 // Now build the command line. 209 char *command = reinterpret_cast<char *>(_alloca(len+1)); 210 char *p = command; 211 212 for (unsigned i = 0; args[i]; i++) { 213 const char *arg = args[i]; 214 const char *start = arg; 215 216 bool needsQuoting = ArgNeedsQuotes(arg); 217 if (needsQuoting) 218 *p++ = '"'; 219 220 while (*arg != '\0') { 221 if (*arg == '\"') { 222 // Escape all preceding escapes (if any), and then escape the quote. 223 p = EscapePrecedingEscapes(p, start, arg); 224 *p++ = '\\'; 225 } 226 227 *p++ = *arg++; 228 } 229 230 if (needsQuoting) { 231 // Make sure our quote doesn't get escaped by a trailing backslash. 232 p = EscapePrecedingEscapes(p, start, arg); 233 *p++ = '"'; 234 } 235 *p++ = ' '; 236 } 237 238 *p = 0; 239 240 // The pointer to the environment block for the new process. 241 char *envblock = 0; 242 243 if (envp) { 244 // An environment block consists of a null-terminated block of 245 // null-terminated strings. Convert the array of environment variables to 246 // an environment block by concatenating them. 247 248 // First, determine the length of the environment block. 249 len = 0; 250 for (unsigned i = 0; envp[i]; i++) 251 len += strlen(envp[i]) + 1; 252 253 // Now build the environment block. 254 envblock = reinterpret_cast<char *>(_alloca(len+1)); 255 p = envblock; 256 257 for (unsigned i = 0; envp[i]; i++) { 258 const char *ev = envp[i]; 259 size_t len = strlen(ev) + 1; 260 memcpy(p, ev, len); 261 p += len; 262 } 263 264 *p = 0; 265 } 266 267 // Create a child process. 268 STARTUPINFO si; 269 memset(&si, 0, sizeof(si)); 270 si.cb = sizeof(si); 271 si.hStdInput = INVALID_HANDLE_VALUE; 272 si.hStdOutput = INVALID_HANDLE_VALUE; 273 si.hStdError = INVALID_HANDLE_VALUE; 274 275 if (redirects) { 276 si.dwFlags = STARTF_USESTDHANDLES; 277 278 si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); 279 if (si.hStdInput == INVALID_HANDLE_VALUE) { 280 MakeErrMsg(ErrMsg, "can't redirect stdin"); 281 return false; 282 } 283 si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); 284 if (si.hStdOutput == INVALID_HANDLE_VALUE) { 285 CloseHandle(si.hStdInput); 286 MakeErrMsg(ErrMsg, "can't redirect stdout"); 287 return false; 288 } 289 if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { 290 // If stdout and stderr should go to the same place, redirect stderr 291 // to the handle already open for stdout. 292 DuplicateHandle(GetCurrentProcess(), si.hStdOutput, 293 GetCurrentProcess(), &si.hStdError, 294 0, TRUE, DUPLICATE_SAME_ACCESS); 295 } else { 296 // Just redirect stderr 297 si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); 298 if (si.hStdError == INVALID_HANDLE_VALUE) { 299 CloseHandle(si.hStdInput); 300 CloseHandle(si.hStdOutput); 301 MakeErrMsg(ErrMsg, "can't redirect stderr"); 302 return false; 303 } 304 } 305 } 306 307 PROCESS_INFORMATION pi; 308 memset(&pi, 0, sizeof(pi)); 309 310 fflush(stdout); 311 fflush(stderr); 312 BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0, 313 envblock, NULL, &si, &pi); 314 DWORD err = GetLastError(); 315 316 // Regardless of whether the process got created or not, we are done with 317 // the handles we created for it to inherit. 318 CloseHandle(si.hStdInput); 319 CloseHandle(si.hStdOutput); 320 CloseHandle(si.hStdError); 321 322 // Now return an error if the process didn't get created. 323 if (!rc) { 324 SetLastError(err); 325 MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + 326 path.str() + "'"); 327 return false; 328 } 329 Win32ProcessInfo* wpi = new Win32ProcessInfo; 330 wpi->hProcess = pi.hProcess; 331 wpi->dwProcessId = pi.dwProcessId; 332 Data_ = wpi; 333 334 // Make sure these get closed no matter what. 335 ScopedCommonHandle hThread(pi.hThread); 336 337 // Assign the process to a job if a memory limit is defined. 338 ScopedJobHandle hJob; 339 if (memoryLimit != 0) { 340 hJob = CreateJobObject(0, 0); 341 bool success = false; 342 if (hJob) { 343 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; 344 memset(&jeli, 0, sizeof(jeli)); 345 jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; 346 jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; 347 if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, 348 &jeli, sizeof(jeli))) { 349 if (AssignProcessToJobObject(hJob, pi.hProcess)) 350 success = true; 351 } 352 } 353 if (!success) { 354 SetLastError(GetLastError()); 355 MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); 356 TerminateProcess(pi.hProcess, 1); 357 WaitForSingleObject(pi.hProcess, INFINITE); 358 return false; 359 } 360 } 361 362 return true; 363} 364 365int 366Program::Wait(const Path &path, 367 unsigned secondsToWait, 368 std::string* ErrMsg) { 369 if (Data_ == 0) { 370 MakeErrMsg(ErrMsg, "Process not started!"); 371 return -1; 372 } 373 374 Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); 375 HANDLE hProcess = wpi->hProcess; 376 377 // Wait for the process to terminate. 378 DWORD millisecondsToWait = INFINITE; 379 if (secondsToWait > 0) 380 millisecondsToWait = secondsToWait * 1000; 381 382 if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { 383 if (!TerminateProcess(hProcess, 1)) { 384 MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); 385 // -2 indicates a crash or timeout as opposed to failure to execute. 386 return -2; 387 } 388 WaitForSingleObject(hProcess, INFINITE); 389 } 390 391 // Get its exit status. 392 DWORD status; 393 BOOL rc = GetExitCodeProcess(hProcess, &status); 394 DWORD err = GetLastError(); 395 396 if (!rc) { 397 SetLastError(err); 398 MakeErrMsg(ErrMsg, "Failed getting status for program."); 399 // -2 indicates a crash or timeout as opposed to failure to execute. 400 return -2; 401 } 402 403 if (!status) 404 return 0; 405 406 // Pass 10(Warning) and 11(Error) to the callee as negative value. 407 if ((status & 0xBFFF0000U) == 0x80000000U) 408 return (int)status; 409 410 if (status & 0xFF) 411 return status & 0x7FFFFFFF; 412 413 return 1; 414} 415 416error_code Program::ChangeStdinToBinary(){ 417 int result = _setmode( _fileno(stdin), _O_BINARY ); 418 if (result == -1) 419 return error_code(errno, generic_category()); 420 return make_error_code(errc::success); 421} 422 423error_code Program::ChangeStdoutToBinary(){ 424 int result = _setmode( _fileno(stdout), _O_BINARY ); 425 if (result == -1) 426 return error_code(errno, generic_category()); 427 return make_error_code(errc::success); 428} 429 430error_code Program::ChangeStderrToBinary(){ 431 int result = _setmode( _fileno(stderr), _O_BINARY ); 432 if (result == -1) 433 return error_code(errno, generic_category()); 434 return make_error_code(errc::success); 435} 436 437bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) { 438 // The documented max length of the command line passed to CreateProcess. 439 static const size_t MaxCommandStringLength = 32768; 440 size_t ArgLength = 0; 441 for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end(); 442 I != E; ++I) { 443 // Account for the trailing space for every arg but the last one and the 444 // trailing NULL of the last argument. 445 ArgLength += ArgLenWithQuotes(*I) + 1; 446 if (ArgLength > MaxCommandStringLength) { 447 return false; 448 } 449 } 450 return true; 451} 452 453} 454