Fix failures on MS-Windows when Make's standard handles are invalid.

This can happen when Make is invoked from a GUI application.

  * w32/subproc/sub_proc.c (process_init_fd): Don't dereference
  pproc if it is a NULL pointer.
  (process_begin, process_cleanup): Don't try to close pipe handles
  whose value is INVALID_HANDLE_VALUE.
  (process_easy): Initialize hIn, hOut, and hErr to
  INVALID_HANDLE_VALUE.  If DuplicateHandle fails with
  ERROR_INVALID_HANDLE, duplicate a handle for the null device
  instead of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE or
  STD_ERROR_HANDLE.  Don't try to close pipe handles whose value is
  INVALID_HANDLE_VALUE.

  * function.c (windows32_openpipe): Initialize hIn and hErr to
  INVALID_HANDLE_VALUE.  If DuplicateHandle fails with
  ERROR_INVALID_HANDLE, duplicate a handle for the null device
  instead of STD_INPUT_HANDLE or STD_ERROR_HANDLE.  Fix indentation.
  Don't try to close handles whose value is INVALID_HANDLE_VALUE.
This commit is contained in:
Eli Zaretskii 2012-01-28 16:50:21 +00:00
parent 715a11735f
commit eb4f966971
3 changed files with 189 additions and 71 deletions

View file

@ -1,3 +1,25 @@
2012-01-28 Eli Zaretskii <eliz@gnu.org>
Fix failures on MS-Windows when Make's standard handles are invalid.
This can happen when Make is invoked from a GUI application.
* w32/subproc/sub_proc.c (process_init_fd): Don't dereference
pproc if it is a NULL pointer.
(process_begin, process_cleanup): Don't try to close pipe handles
whose value is INVALID_HANDLE_VALUE.
(process_easy): Initialize hIn, hOut, and hErr to
INVALID_HANDLE_VALUE. If DuplicateHandle fails with
ERROR_INVALID_HANDLE, duplicate a handle for the null device
instead of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE or
STD_ERROR_HANDLE. Don't try to close pipe handles whose value is
INVALID_HANDLE_VALUE.
* function.c (windows32_openpipe): Initialize hIn and hErr to
INVALID_HANDLE_VALUE. If DuplicateHandle fails with
ERROR_INVALID_HANDLE, duplicate a handle for the null device
instead of STD_INPUT_HANDLE or STD_ERROR_HANDLE. Fix indentation.
Don't try to close handles whose value is INVALID_HANDLE_VALUE.
2012-01-25 Eli Zaretskii <eliz@gnu.org> 2012-01-25 Eli Zaretskii <eliz@gnu.org>
* function.c (define_new_function): Fix format strings in calls to * function.c (define_new_function): Fix format strings in calls to

View file

@ -1434,37 +1434,70 @@ void
windows32_openpipe (int *pipedes, pid_t *pid_p, char **command_argv, char **envp) windows32_openpipe (int *pipedes, pid_t *pid_p, char **command_argv, char **envp)
{ {
SECURITY_ATTRIBUTES saAttr; SECURITY_ATTRIBUTES saAttr;
HANDLE hIn; HANDLE hIn = INVALID_HANDLE_VALUE;
HANDLE hErr; HANDLE hErr = INVALID_HANDLE_VALUE;
HANDLE hChildOutRd; HANDLE hChildOutRd;
HANDLE hChildOutWr; HANDLE hChildOutWr;
HANDLE hProcess; HANDLE hProcess, tmpIn, tmpErr;
DWORD e;
saAttr.nLength = sizeof (SECURITY_ATTRIBUTES); saAttr.nLength = sizeof (SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL; saAttr.lpSecurityDescriptor = NULL;
/* Standard handles returned by GetStdHandle can be NULL or
INVALID_HANDLE_VALUE if the parent process closed them. If that
happens, we open the null device and pass its handle to
process_begin below as the corresponding handle to inherit. */
tmpIn = GetStdHandle(STD_INPUT_HANDLE);
if (DuplicateHandle (GetCurrentProcess(), if (DuplicateHandle (GetCurrentProcess(),
GetStdHandle(STD_INPUT_HANDLE), tmpIn,
GetCurrentProcess(), GetCurrentProcess(),
&hIn, &hIn,
0, 0,
TRUE, TRUE,
DUPLICATE_SAME_ACCESS) == FALSE) { DUPLICATE_SAME_ACCESS) == FALSE) {
fatal (NILF, _("windows32_openpipe(): DuplicateHandle(In) failed (e=%ld)\n"), if ((e = GetLastError()) == ERROR_INVALID_HANDLE) {
GetLastError()); tmpIn = CreateFile("NUL", GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (tmpIn != INVALID_HANDLE_VALUE
&& DuplicateHandle(GetCurrentProcess(),
tmpIn,
GetCurrentProcess(),
&hIn,
0,
TRUE,
DUPLICATE_SAME_ACCESS) == FALSE)
CloseHandle(tmpIn);
}
if (hIn == INVALID_HANDLE_VALUE)
fatal (NILF, _("windows32_openpipe: DuplicateHandle(In) failed (e=%ld)\n"), e);
} }
tmpErr = GetStdHandle(STD_ERROR_HANDLE);
if (DuplicateHandle(GetCurrentProcess(), if (DuplicateHandle(GetCurrentProcess(),
GetStdHandle(STD_ERROR_HANDLE), tmpErr,
GetCurrentProcess(), GetCurrentProcess(),
&hErr, &hErr,
0, 0,
TRUE, TRUE,
DUPLICATE_SAME_ACCESS) == FALSE) { DUPLICATE_SAME_ACCESS) == FALSE) {
fatal (NILF, _("windows32_open_pipe(): DuplicateHandle(Err) failed (e=%ld)\n"), if ((e = GetLastError()) == ERROR_INVALID_HANDLE) {
GetLastError()); tmpErr = CreateFile("NUL", GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (tmpErr != INVALID_HANDLE_VALUE
&& DuplicateHandle(GetCurrentProcess(),
tmpErr,
GetCurrentProcess(),
&hErr,
0,
TRUE,
DUPLICATE_SAME_ACCESS) == FALSE)
CloseHandle(tmpErr);
}
if (hErr == INVALID_HANDLE_VALUE)
fatal (NILF, _("windows32_openpipe: DuplicateHandle(Err) failed (e=%ld)\n"), e);
} }
if (!CreatePipe(&hChildOutRd, &hChildOutWr, &saAttr, 0)) if (!CreatePipe(&hChildOutRd, &hChildOutWr, &saAttr, 0))
@ -1483,23 +1516,25 @@ windows32_openpipe (int *pipedes, pid_t *pid_p, char **command_argv, char **envp
if (!process_begin(hProcess, command_argv, envp, command_argv[0], NULL)) { if (!process_begin(hProcess, command_argv, envp, command_argv[0], NULL)) {
/* register process for wait */ /* register process for wait */
process_register(hProcess); process_register(hProcess);
/* set the pid for returning to caller */ /* set the pid for returning to caller */
*pid_p = (pid_t) hProcess; *pid_p = (pid_t) hProcess;
/* set up to read data from child */ /* set up to read data from child */
pipedes[0] = _open_osfhandle((intptr_t) hChildOutRd, O_RDONLY); pipedes[0] = _open_osfhandle((intptr_t) hChildOutRd, O_RDONLY);
/* this will be closed almost right away */ /* this will be closed almost right away */
pipedes[1] = _open_osfhandle((intptr_t) hChildOutWr, O_APPEND); pipedes[1] = _open_osfhandle((intptr_t) hChildOutWr, O_APPEND);
} else { } else {
/* reap/cleanup the failed process */ /* reap/cleanup the failed process */
process_cleanup(hProcess); process_cleanup(hProcess);
/* close handles which were duplicated, they weren't used */ /* close handles which were duplicated, they weren't used */
CloseHandle(hIn); if (hIn != INVALID_HANDLE_VALUE)
CloseHandle(hErr); CloseHandle(hIn);
if (hErr != INVALID_HANDLE_VALUE)
CloseHandle(hErr);
/* close pipe handles, they won't be used */ /* close pipe handles, they won't be used */
CloseHandle(hChildOutRd); CloseHandle(hChildOutRd);

View file

@ -462,17 +462,19 @@ process_init_fd(HANDLE stdinh, HANDLE stdouth, HANDLE stderrh)
sub_process *pproc; sub_process *pproc;
pproc = malloc(sizeof(*pproc)); pproc = malloc(sizeof(*pproc));
memset(pproc, 0, sizeof(*pproc)); if (pproc) {
memset(pproc, 0, sizeof(*pproc));
/* /*
* Just pass the provided file handles to the 'child side' of the * Just pass the provided file handles to the 'child
* pipe, bypassing pipes altogether. * side' of the pipe, bypassing pipes altogether.
*/ */
pproc->sv_stdin[1] = (intptr_t) stdinh; pproc->sv_stdin[1] = (intptr_t) stdinh;
pproc->sv_stdout[1] = (intptr_t) stdouth; pproc->sv_stdout[1] = (intptr_t) stdouth;
pproc->sv_stderr[1] = (intptr_t) stderrh; pproc->sv_stderr[1] = (intptr_t) stderrh;
pproc->last_err = pproc->lerrno = 0; pproc->last_err = pproc->lerrno = 0;
}
return((HANDLE)pproc); return((HANDLE)pproc);
} }
@ -711,9 +713,12 @@ process_begin(
CloseHandle(procInfo.hThread); CloseHandle(procInfo.hThread);
/* Close the halves of the pipes we don't need */ /* Close the halves of the pipes we don't need */
CloseHandle((HANDLE)pproc->sv_stdin[1]); if ((HANDLE)pproc->sv_stdin[1] != INVALID_HANDLE_VALUE)
CloseHandle((HANDLE)pproc->sv_stdout[1]); CloseHandle((HANDLE)pproc->sv_stdin[1]);
CloseHandle((HANDLE)pproc->sv_stderr[1]); if ((HANDLE)pproc->sv_stdout[1] != INVALID_HANDLE_VALUE)
CloseHandle((HANDLE)pproc->sv_stdout[1]);
if ((HANDLE)pproc->sv_stderr[1] != INVALID_HANDLE_VALUE)
CloseHandle((HANDLE)pproc->sv_stderr[1]);
pproc->sv_stdin[1] = 0; pproc->sv_stdin[1] = 0;
pproc->sv_stdout[1] = 0; pproc->sv_stdout[1] = 0;
pproc->sv_stderr[1] = 0; pproc->sv_stderr[1] = 0;
@ -1064,11 +1069,14 @@ process_cleanup(
if (pproc->using_pipes) { if (pproc->using_pipes) {
for (i= 0; i <= 1; i++) { for (i= 0; i <= 1; i++) {
if ((HANDLE)pproc->sv_stdin[i]) if ((HANDLE)pproc->sv_stdin[i]
&& (HANDLE)pproc->sv_stdin[i] != INVALID_HANDLE_VALUE)
CloseHandle((HANDLE)pproc->sv_stdin[i]); CloseHandle((HANDLE)pproc->sv_stdin[i]);
if ((HANDLE)pproc->sv_stdout[i]) if ((HANDLE)pproc->sv_stdout[i]
&& (HANDLE)pproc->sv_stdout[i] != INVALID_HANDLE_VALUE)
CloseHandle((HANDLE)pproc->sv_stdout[i]); CloseHandle((HANDLE)pproc->sv_stdout[i]);
if ((HANDLE)pproc->sv_stderr[i]) if ((HANDLE)pproc->sv_stderr[i]
&& (HANDLE)pproc->sv_stderr[i] != INVALID_HANDLE_VALUE)
CloseHandle((HANDLE)pproc->sv_stderr[i]); CloseHandle((HANDLE)pproc->sv_stderr[i]);
} }
} }
@ -1333,50 +1341,100 @@ process_easy(
char **argv, char **argv,
char **envp) char **envp)
{ {
HANDLE hIn; HANDLE hIn = INVALID_HANDLE_VALUE;
HANDLE hOut; HANDLE hOut = INVALID_HANDLE_VALUE;
HANDLE hErr; HANDLE hErr = INVALID_HANDLE_VALUE;
HANDLE hProcess; HANDLE hProcess, tmpIn, tmpOut, tmpErr;
DWORD e;
if (proc_index >= MAXIMUM_WAIT_OBJECTS) { if (proc_index >= MAXIMUM_WAIT_OBJECTS) {
DB (DB_JOBS, ("process_easy: All process slots used up\n")); DB (DB_JOBS, ("process_easy: All process slots used up\n"));
return INVALID_HANDLE_VALUE; return INVALID_HANDLE_VALUE;
} }
/* Standard handles returned by GetStdHandle can be NULL or
INVALID_HANDLE_VALUE if the parent process closed them. If that
happens, we open the null device and pass its handle to
CreateProcess as the corresponding handle to inherit. */
tmpIn = GetStdHandle(STD_INPUT_HANDLE);
if (DuplicateHandle(GetCurrentProcess(), if (DuplicateHandle(GetCurrentProcess(),
GetStdHandle(STD_INPUT_HANDLE), tmpIn,
GetCurrentProcess(), GetCurrentProcess(),
&hIn, &hIn,
0, 0,
TRUE, TRUE,
DUPLICATE_SAME_ACCESS) == FALSE) { DUPLICATE_SAME_ACCESS) == FALSE) {
fprintf(stderr, if ((e = GetLastError()) == ERROR_INVALID_HANDLE) {
"process_easy: DuplicateHandle(In) failed (e=%ld)\n", tmpIn = CreateFile("NUL", GENERIC_READ,
GetLastError()); FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
return INVALID_HANDLE_VALUE; OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (tmpIn != INVALID_HANDLE_VALUE
&& DuplicateHandle(GetCurrentProcess(),
tmpIn,
GetCurrentProcess(),
&hIn,
0,
TRUE,
DUPLICATE_SAME_ACCESS) == FALSE)
CloseHandle(tmpIn);
}
if (hIn == INVALID_HANDLE_VALUE) {
fprintf(stderr, "process_easy: DuplicateHandle(In) failed (e=%ld)\n", e);
return INVALID_HANDLE_VALUE;
}
} }
tmpOut = GetStdHandle (STD_OUTPUT_HANDLE);
if (DuplicateHandle(GetCurrentProcess(), if (DuplicateHandle(GetCurrentProcess(),
GetStdHandle(STD_OUTPUT_HANDLE), tmpOut,
GetCurrentProcess(), GetCurrentProcess(),
&hOut, &hOut,
0, 0,
TRUE, TRUE,
DUPLICATE_SAME_ACCESS) == FALSE) { DUPLICATE_SAME_ACCESS) == FALSE) {
fprintf(stderr, if ((e = GetLastError()) == ERROR_INVALID_HANDLE) {
"process_easy: DuplicateHandle(Out) failed (e=%ld)\n", tmpOut = CreateFile("NUL", GENERIC_WRITE,
GetLastError()); FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
return INVALID_HANDLE_VALUE; OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (tmpOut != INVALID_HANDLE_VALUE
&& DuplicateHandle(GetCurrentProcess(),
tmpOut,
GetCurrentProcess(),
&hOut,
0,
TRUE,
DUPLICATE_SAME_ACCESS) == FALSE)
CloseHandle(tmpOut);
}
if (hOut == INVALID_HANDLE_VALUE) {
fprintf(stderr, "process_easy: DuplicateHandle(Out) failed (e=%ld)\n", e);
return INVALID_HANDLE_VALUE;
}
} }
tmpErr = GetStdHandle(STD_ERROR_HANDLE);
if (DuplicateHandle(GetCurrentProcess(), if (DuplicateHandle(GetCurrentProcess(),
GetStdHandle(STD_ERROR_HANDLE), tmpErr,
GetCurrentProcess(), GetCurrentProcess(),
&hErr, &hErr,
0, 0,
TRUE, TRUE,
DUPLICATE_SAME_ACCESS) == FALSE) { DUPLICATE_SAME_ACCESS) == FALSE) {
fprintf(stderr, if ((e = GetLastError()) == ERROR_INVALID_HANDLE) {
"process_easy: DuplicateHandle(Err) failed (e=%ld)\n", tmpErr = CreateFile("NUL", GENERIC_WRITE,
GetLastError()); FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
return INVALID_HANDLE_VALUE; OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (tmpErr != INVALID_HANDLE_VALUE
&& DuplicateHandle(GetCurrentProcess(),
tmpErr,
GetCurrentProcess(),
&hErr,
0,
TRUE,
DUPLICATE_SAME_ACCESS) == FALSE)
CloseHandle(tmpErr);
}
if (hErr == INVALID_HANDLE_VALUE) {
fprintf(stderr, "process_easy: DuplicateHandle(Err) failed (e=%ld)\n", e);
return INVALID_HANDLE_VALUE;
}
} }
hProcess = process_init_fd(hIn, hOut, hErr); hProcess = process_init_fd(hIn, hOut, hErr);
@ -1389,9 +1447,12 @@ process_easy(
((sub_process*) hProcess)->exit_code = process_last_err(hProcess); ((sub_process*) hProcess)->exit_code = process_last_err(hProcess);
/* close up unused handles */ /* close up unused handles */
CloseHandle(hIn); if (hIn != INVALID_HANDLE_VALUE)
CloseHandle(hOut); CloseHandle(hIn);
CloseHandle(hErr); if (hOut != INVALID_HANDLE_VALUE)
CloseHandle(hOut);
if (hErr != INVALID_HANDLE_VALUE)
CloseHandle(hErr);
} }
process_register(hProcess); process_register(hProcess);