forked from OSchip/llvm-project
[Support] Fix handle and memory leak for processes that are not waited for
Execute's Data parameter is now optional, so we won't allocate memory for it on Windows and we'll close the process handle. The Unix code should probably do something similar to avoid accumulation of zombie children that haven't been waited on. Tested on Linux and Windows. llvm-svn: 183906
This commit is contained in:
parent
92509c1c0c
commit
6e6a0f50b3
|
@ -22,7 +22,7 @@ using namespace sys;
|
||||||
//=== independent code.
|
//=== independent code.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
static bool Execute(void *&Data, const Path &path, const char **args,
|
static bool Execute(void **Data, const Path &path, const char **args,
|
||||||
const char **env, const sys::Path **redirects,
|
const char **env, const sys::Path **redirects,
|
||||||
unsigned memoryLimit, std::string *ErrMsg);
|
unsigned memoryLimit, std::string *ErrMsg);
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ int sys::ExecuteAndWait(const Path &path, const char **args, const char **envp,
|
||||||
unsigned memoryLimit, std::string *ErrMsg,
|
unsigned memoryLimit, std::string *ErrMsg,
|
||||||
bool *ExecutionFailed) {
|
bool *ExecutionFailed) {
|
||||||
void *Data = 0;
|
void *Data = 0;
|
||||||
if (Execute(Data, path, args, envp, redirects, memoryLimit, ErrMsg)) {
|
if (Execute(&Data, path, args, envp, redirects, memoryLimit, ErrMsg)) {
|
||||||
if (ExecutionFailed) *ExecutionFailed = false;
|
if (ExecutionFailed) *ExecutionFailed = false;
|
||||||
return Wait(Data, path, secondsToWait, ErrMsg);
|
return Wait(Data, path, secondsToWait, ErrMsg);
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,7 @@ int sys::ExecuteAndWait(const Path &path, const char **args, const char **envp,
|
||||||
void sys::ExecuteNoWait(const Path &path, const char **args, const char **envp,
|
void sys::ExecuteNoWait(const Path &path, const char **args, const char **envp,
|
||||||
const Path **redirects, unsigned memoryLimit,
|
const Path **redirects, unsigned memoryLimit,
|
||||||
std::string *ErrMsg) {
|
std::string *ErrMsg) {
|
||||||
void *Data = 0;
|
Execute(/*Data*/ 0, path, args, envp, redirects, memoryLimit, ErrMsg);
|
||||||
Execute(Data, path, args, envp, redirects, memoryLimit, ErrMsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include the platform-specific parts of this class.
|
// Include the platform-specific parts of this class.
|
||||||
|
|
|
@ -178,7 +178,7 @@ static void SetMemoryLimits (unsigned size)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Execute(void *&Data, const Path &path, const char **args,
|
static bool Execute(void **Data, const Path &path, const char **args,
|
||||||
const char **envp, const Path **redirects,
|
const char **envp, const Path **redirects,
|
||||||
unsigned memoryLimit, std::string *ErrMsg) {
|
unsigned memoryLimit, std::string *ErrMsg) {
|
||||||
// If this OS has posix_spawn and there is no memory limit being implied, use
|
// If this OS has posix_spawn and there is no memory limit being implied, use
|
||||||
|
@ -228,7 +228,8 @@ static bool Execute(void *&Data, const Path &path, const char **args,
|
||||||
if (Err)
|
if (Err)
|
||||||
return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
|
return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
|
||||||
|
|
||||||
Data = reinterpret_cast<void*>(PID);
|
if (Data)
|
||||||
|
*Data = reinterpret_cast<void*>(PID);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -290,7 +291,8 @@ static bool Execute(void *&Data, const Path &path, const char **args,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Data = reinterpret_cast<void*>(child);
|
if (Data)
|
||||||
|
*Data = reinterpret_cast<void*>(child);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -299,11 +301,7 @@ static int Wait(void *&Data, const sys::Path &path, unsigned secondsToWait,
|
||||||
std::string *ErrMsg) {
|
std::string *ErrMsg) {
|
||||||
#ifdef HAVE_SYS_WAIT_H
|
#ifdef HAVE_SYS_WAIT_H
|
||||||
struct sigaction Act, Old;
|
struct sigaction Act, Old;
|
||||||
|
assert(Data && "invalid pid to wait on, process not started?");
|
||||||
if (Data == 0) {
|
|
||||||
MakeErrMsg(ErrMsg, "Process not started!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install a timeout handler. The handler itself does nothing, but the simple
|
// Install a timeout handler. The handler itself does nothing, but the simple
|
||||||
// fact of having a handler at all causes the wait below to return with EINTR,
|
// fact of having a handler at all causes the wait below to return with EINTR,
|
||||||
|
|
|
@ -170,20 +170,13 @@ static unsigned int ArgLenWithQuotes(const char *Str) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Execute(void *&Data,
|
static bool Execute(void **Data,
|
||||||
const Path& path,
|
const Path& path,
|
||||||
const char** args,
|
const char** args,
|
||||||
const char** envp,
|
const char** envp,
|
||||||
const Path** redirects,
|
const Path** redirects,
|
||||||
unsigned memoryLimit,
|
unsigned memoryLimit,
|
||||||
std::string* ErrMsg) {
|
std::string* ErrMsg) {
|
||||||
if (Data) {
|
|
||||||
Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data);
|
|
||||||
CloseHandle(wpi->hProcess);
|
|
||||||
delete wpi;
|
|
||||||
Data = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!path.canExecute()) {
|
if (!path.canExecute()) {
|
||||||
if (ErrMsg)
|
if (ErrMsg)
|
||||||
*ErrMsg = "program not executable";
|
*ErrMsg = "program not executable";
|
||||||
|
@ -321,10 +314,12 @@ static bool Execute(void *&Data,
|
||||||
path.str() + "'");
|
path.str() + "'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Win32ProcessInfo* wpi = new Win32ProcessInfo;
|
if (Data) {
|
||||||
wpi->hProcess = pi.hProcess;
|
Win32ProcessInfo* wpi = new Win32ProcessInfo;
|
||||||
wpi->dwProcessId = pi.dwProcessId;
|
wpi->hProcess = pi.hProcess;
|
||||||
Data = wpi;
|
wpi->dwProcessId = pi.dwProcessId;
|
||||||
|
*Data = wpi;
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure these get closed no matter what.
|
// Make sure these get closed no matter what.
|
||||||
ScopedCommonHandle hThread(pi.hThread);
|
ScopedCommonHandle hThread(pi.hThread);
|
||||||
|
@ -354,21 +349,17 @@ static bool Execute(void *&Data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't leak the handle if the caller doesn't want it.
|
||||||
|
if (!Data)
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int WaitAux(void *&Data, const Path &path,
|
static int WaitAux(Win32ProcessInfo *wpi, const Path &path,
|
||||||
unsigned secondsToWait,
|
unsigned secondsToWait, std::string *ErrMsg) {
|
||||||
std::string* ErrMsg) {
|
|
||||||
if (Data == 0) {
|
|
||||||
MakeErrMsg(ErrMsg, "Process not started!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data);
|
|
||||||
HANDLE hProcess = wpi->hProcess;
|
|
||||||
|
|
||||||
// Wait for the process to terminate.
|
// Wait for the process to terminate.
|
||||||
|
HANDLE hProcess = wpi->hProcess;
|
||||||
DWORD millisecondsToWait = INFINITE;
|
DWORD millisecondsToWait = INFINITE;
|
||||||
if (secondsToWait > 0)
|
if (secondsToWait > 0)
|
||||||
millisecondsToWait = secondsToWait * 1000;
|
millisecondsToWait = secondsToWait * 1000;
|
||||||
|
@ -407,12 +398,11 @@ static int WaitAux(void *&Data, const Path &path,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Wait(void *&Data, const Path &path,
|
static int Wait(void *&Data, const Path &path, unsigned secondsToWait,
|
||||||
unsigned secondsToWait,
|
std::string *ErrMsg) {
|
||||||
std::string* ErrMsg) {
|
Win32ProcessInfo *wpi = reinterpret_cast<Win32ProcessInfo *>(Data);
|
||||||
int Ret = WaitAux(Data, path, secondsToWait, ErrMsg);
|
int Ret = WaitAux(wpi, path, secondsToWait, ErrMsg);
|
||||||
|
|
||||||
Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data);
|
|
||||||
CloseHandle(wpi->hProcess);
|
CloseHandle(wpi->hProcess);
|
||||||
delete wpi;
|
delete wpi;
|
||||||
Data = 0;
|
Data = 0;
|
||||||
|
|
Loading…
Reference in New Issue