LLVM API Documentation
00001 //===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file provides the Win32 specific implementation of the Program class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "Win32.h" 00015 #include <cstdio> 00016 #include <malloc.h> 00017 #include <io.h> 00018 #include <fcntl.h> 00019 00020 //===----------------------------------------------------------------------===// 00021 //=== WARNING: Implementation here must contain only Win32 specific code 00022 //=== and must not be UNIX code 00023 //===----------------------------------------------------------------------===// 00024 00025 namespace llvm { 00026 using namespace sys; 00027 00028 // This function just uses the PATH environment variable to find the program. 00029 Path 00030 Program::FindProgramByName(const std::string& progName) { 00031 00032 // Check some degenerate cases 00033 if (progName.length() == 0) // no program 00034 return Path(); 00035 Path temp; 00036 if (!temp.set(progName)) // invalid name 00037 return Path(); 00038 if (temp.canExecute()) // already executable as is 00039 return temp; 00040 00041 // At this point, the file name is valid and its not executable. 00042 // Let Windows search for it. 00043 char buffer[MAX_PATH]; 00044 char *dummy = NULL; 00045 DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, 00046 buffer, &dummy); 00047 00048 // See if it wasn't found. 00049 if (len == 0) 00050 return Path(); 00051 00052 // See if we got the entire path. 00053 if (len < MAX_PATH) 00054 return Path(buffer); 00055 00056 // Buffer was too small; grow and retry. 00057 while (true) { 00058 char *b = reinterpret_cast<char *>(_alloca(len+1)); 00059 DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); 00060 00061 // It is unlikely the search failed, but it's always possible some file 00062 // was added or removed since the last search, so be paranoid... 00063 if (len2 == 0) 00064 return Path(); 00065 else if (len2 <= len) 00066 return Path(b); 00067 00068 len = len2; 00069 } 00070 } 00071 00072 static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { 00073 HANDLE h; 00074 if (path == 0) { 00075 DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), 00076 GetCurrentProcess(), &h, 00077 0, TRUE, DUPLICATE_SAME_ACCESS); 00078 return h; 00079 } 00080 00081 const char *fname; 00082 if (path->isEmpty()) 00083 fname = "NUL"; 00084 else 00085 fname = path->toString().c_str(); 00086 00087 SECURITY_ATTRIBUTES sa; 00088 sa.nLength = sizeof(sa); 00089 sa.lpSecurityDescriptor = 0; 00090 sa.bInheritHandle = TRUE; 00091 00092 h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, 00093 &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, 00094 FILE_ATTRIBUTE_NORMAL, NULL); 00095 if (h == INVALID_HANDLE_VALUE) { 00096 MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + 00097 (fd ? "input: " : "output: ")); 00098 } 00099 00100 return h; 00101 } 00102 00103 #ifdef __MINGW32__ 00104 // Due to unknown reason, mingw32's w32api doesn't have this declaration. 00105 extern "C" 00106 BOOL WINAPI SetInformationJobObject(HANDLE hJob, 00107 JOBOBJECTINFOCLASS JobObjectInfoClass, 00108 LPVOID lpJobObjectInfo, 00109 DWORD cbJobObjectInfoLength); 00110 #endif 00111 00112 int 00113 Program::ExecuteAndWait(const Path& path, 00114 const char** args, 00115 const char** envp, 00116 const Path** redirects, 00117 unsigned secondsToWait, 00118 unsigned memoryLimit, 00119 std::string* ErrMsg) { 00120 if (!path.canExecute()) { 00121 if (ErrMsg) 00122 *ErrMsg = "program not executable"; 00123 return -1; 00124 } 00125 00126 // Windows wants a command line, not an array of args, to pass to the new 00127 // process. We have to concatenate them all, while quoting the args that 00128 // have embedded spaces. 00129 00130 // First, determine the length of the command line. 00131 unsigned len = 0; 00132 for (unsigned i = 0; args[i]; i++) { 00133 len += strlen(args[i]) + 1; 00134 if (strchr(args[i], ' ')) 00135 len += 2; 00136 } 00137 00138 // Now build the command line. 00139 char *command = reinterpret_cast<char *>(_alloca(len+1)); 00140 char *p = command; 00141 00142 for (unsigned i = 0; args[i]; i++) { 00143 const char *arg = args[i]; 00144 size_t len = strlen(arg); 00145 bool needsQuoting = strchr(arg, ' ') != 0; 00146 if (needsQuoting) 00147 *p++ = '"'; 00148 memcpy(p, arg, len); 00149 p += len; 00150 if (needsQuoting) 00151 *p++ = '"'; 00152 *p++ = ' '; 00153 } 00154 00155 *p = 0; 00156 00157 // The pointer to the environment block for the new process. 00158 char *envblock = 0; 00159 00160 if (envp) { 00161 // An environment block consists of a null-terminated block of 00162 // null-terminated strings. Convert the array of environment variables to 00163 // an environment block by concatenating them. 00164 00165 // First, determine the length of the environment block. 00166 len = 0; 00167 for (unsigned i = 0; envp[i]; i++) 00168 len += strlen(envp[i]) + 1; 00169 00170 // Now build the environment block. 00171 envblock = reinterpret_cast<char *>(_alloca(len+1)); 00172 p = envblock; 00173 00174 for (unsigned i = 0; envp[i]; i++) { 00175 const char *ev = envp[i]; 00176 size_t len = strlen(ev) + 1; 00177 memcpy(p, ev, len); 00178 p += len; 00179 } 00180 00181 *p = 0; 00182 } 00183 00184 // Create a child process. 00185 STARTUPINFO si; 00186 memset(&si, 0, sizeof(si)); 00187 si.cb = sizeof(si); 00188 si.hStdInput = INVALID_HANDLE_VALUE; 00189 si.hStdOutput = INVALID_HANDLE_VALUE; 00190 si.hStdError = INVALID_HANDLE_VALUE; 00191 00192 if (redirects) { 00193 si.dwFlags = STARTF_USESTDHANDLES; 00194 00195 si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); 00196 if (si.hStdInput == INVALID_HANDLE_VALUE) { 00197 MakeErrMsg(ErrMsg, "can't redirect stdin"); 00198 return -1; 00199 } 00200 si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); 00201 if (si.hStdOutput == INVALID_HANDLE_VALUE) { 00202 CloseHandle(si.hStdInput); 00203 MakeErrMsg(ErrMsg, "can't redirect stdout"); 00204 return -1; 00205 } 00206 if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { 00207 // If stdout and stderr should go to the same place, redirect stderr 00208 // to the handle already open for stdout. 00209 DuplicateHandle(GetCurrentProcess(), si.hStdOutput, 00210 GetCurrentProcess(), &si.hStdError, 00211 0, TRUE, DUPLICATE_SAME_ACCESS); 00212 } else { 00213 // Just redirect stderr 00214 si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); 00215 if (si.hStdError == INVALID_HANDLE_VALUE) { 00216 CloseHandle(si.hStdInput); 00217 CloseHandle(si.hStdOutput); 00218 MakeErrMsg(ErrMsg, "can't redirect stderr"); 00219 return -1; 00220 } 00221 } 00222 } 00223 00224 PROCESS_INFORMATION pi; 00225 memset(&pi, 0, sizeof(pi)); 00226 00227 fflush(stdout); 00228 fflush(stderr); 00229 BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, FALSE, 0, 00230 envblock, NULL, &si, &pi); 00231 DWORD err = GetLastError(); 00232 00233 // Regardless of whether the process got created or not, we are done with 00234 // the handles we created for it to inherit. 00235 CloseHandle(si.hStdInput); 00236 CloseHandle(si.hStdOutput); 00237 CloseHandle(si.hStdError); 00238 00239 // Now return an error if the process didn't get created. 00240 if (!rc) 00241 { 00242 SetLastError(err); 00243 MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + 00244 path.toString() + "'"); 00245 return -1; 00246 } 00247 00248 // Make sure these get closed no matter what. 00249 AutoHandle hProcess(pi.hProcess); 00250 AutoHandle hThread(pi.hThread); 00251 00252 // Assign the process to a job if a memory limit is defined. 00253 AutoHandle hJob(0); 00254 if (memoryLimit != 0) { 00255 hJob = CreateJobObject(0, 0); 00256 bool success = false; 00257 if (hJob != 0) { 00258 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; 00259 memset(&jeli, 0, sizeof(jeli)); 00260 jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; 00261 jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; 00262 if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, 00263 &jeli, sizeof(jeli))) { 00264 if (AssignProcessToJobObject(hJob, pi.hProcess)) 00265 success = true; 00266 } 00267 } 00268 if (!success) { 00269 SetLastError(GetLastError()); 00270 MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); 00271 TerminateProcess(pi.hProcess, 1); 00272 WaitForSingleObject(pi.hProcess, INFINITE); 00273 return -1; 00274 } 00275 } 00276 00277 // Wait for it to terminate. 00278 DWORD millisecondsToWait = INFINITE; 00279 if (secondsToWait > 0) 00280 millisecondsToWait = secondsToWait * 1000; 00281 00282 if (WaitForSingleObject(pi.hProcess, millisecondsToWait) == WAIT_TIMEOUT) { 00283 if (!TerminateProcess(pi.hProcess, 1)) { 00284 MakeErrMsg(ErrMsg, std::string("Failed to terminate timed-out program '") 00285 + path.toString() + "'"); 00286 return -1; 00287 } 00288 WaitForSingleObject(pi.hProcess, INFINITE); 00289 } 00290 00291 // Get its exit status. 00292 DWORD status; 00293 rc = GetExitCodeProcess(pi.hProcess, &status); 00294 err = GetLastError(); 00295 00296 if (!rc) { 00297 SetLastError(err); 00298 MakeErrMsg(ErrMsg, std::string("Failed getting status for program '") + 00299 path.toString() + "'"); 00300 return -1; 00301 } 00302 00303 return status; 00304 } 00305 00306 bool Program::ChangeStdinToBinary(){ 00307 int result = _setmode( _fileno(stdin), _O_BINARY ); 00308 return result == -1; 00309 } 00310 00311 bool Program::ChangeStdoutToBinary(){ 00312 int result = _setmode( _fileno(stdout), _O_BINARY ); 00313 return result == -1; 00314 } 00315 00316 }