Skip to content

Commit

Permalink
win,process: avoid kernel bug with starting Windows Store apps
Browse files Browse the repository at this point in the history
Make sure this handle is functional. The Windows kernel seems to have a bug that if the first use of AssignProcessToJobObject is for a Windows Store program, subsequent attempts to use the handle with fail with INVALID_PARAMETER (87). This is possilby because all uses of the handle must be for the same Terminal Services session. We can ensure it is tied to our current session now by adding ourself to it. We could remove ourself afterwards, but there doesn't seem to be a reason to.

Secondly, we start the process suspended so that we can make sure we added it
to the job control object before it does anything itself (such as launch more
jobs or exit).

Fixes: JuliaLang/julia#51461
  • Loading branch information
vtjnash committed Sep 27, 2023
1 parent d277f71 commit 93ca3f1
Showing 1 changed file with 29 additions and 5 deletions.
34 changes: 29 additions & 5 deletions src/win/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,21 @@ static void uv__init_global_job_handle(void) {
&info,
sizeof info))
uv_fatal_error(GetLastError(), "SetInformationJobObject");


if (!AssignProcessToJobObject(uv_global_job_handle_, GetCurrentProcess())) {
/* Make sure this handle is functional. The Windows kernel has a bug that
* if the first use of AssignProcessToJobObject is for a Windows Store
* program, subsequent attempts to use the handle with fail with
* INVALID_PARAMETER (87). This is possilby because all uses of the handle
* must be for the same Terminal Services session. We can ensure it is tied
* to our current session now by adding ourself to it. We could remove
* ourself afterwards, but there doesn't seem to be a reason to.
*/
DWORD err = GetLastError();
if (err != ERROR_ACCESS_DENIED)
uv_fatal_error(err, "AssignProcessToJobObject");
}
}


Expand Down Expand Up @@ -1099,6 +1114,7 @@ int uv_spawn(uv_loop_t* loop,
* breakaway.
*/
process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
process_flags |= CREATE_SUSPENDED;
}

if (!CreateProcessW(application_path,
Expand All @@ -1116,11 +1132,6 @@ int uv_spawn(uv_loop_t* loop,
goto done;
}

/* Spawn succeeded. Beyond this point, failure is reported asynchronously. */

process->process_handle = info.hProcess;
process->pid = info.dwProcessId;

/* If the process isn't spawned as detached, assign to the global job object
* so windows will kill it when the parent process dies. */
if (!(options->flags & UV_PROCESS_DETACHED)) {
Expand All @@ -1143,6 +1154,19 @@ int uv_spawn(uv_loop_t* loop,
}
}

if (process_flags & CREATE_SUSPENDED) {
if (ResumeThread(info.hThread) == ((DWORD)-1)) {
err = GetLastError();
TerminateProcess(info.hProcess, 1);
goto done;
}
}

/* Spawn succeeded. Beyond this point, failure is reported asynchronously. */

process->process_handle = info.hProcess;
process->pid = info.dwProcessId;

/* Set IPC pid to all IPC pipes. */
for (i = 0; i < options->stdio_count; i++) {
const uv_stdio_container_t* fdopt = &options->stdio[i];
Expand Down

0 comments on commit 93ca3f1

Please sign in to comment.