Skip to content

Commit 6416deb

Browse files
santigimenovtjnash
authored andcommitted
win: almost fix race detecting ESRCH in uv_kill (libuv#4341)
It might happen that only using `WaitForSingleObject()` with timeout 0 could return WAIT_TIMEOUT as the process might not have been signaled yet. To improve things, first use `GetExitCodeProcess()` and check that `status` is not `STILL_ACTIVE`. Then, to cover for the case that the exit code was actually `STILL_ACTIVE` use `WaitForSingleObject()`. This could still be prone to the race condition but only for that case.
1 parent fa16125 commit 6416deb

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

src/win/process.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,23 +1364,49 @@ static int uv__kill(HANDLE process_handle, int signum) {
13641364
/* Unconditionally terminate the process. On Windows, killed processes
13651365
* normally return 1. */
13661366
int err;
1367+
DWORD status;
13671368

13681369
if (TerminateProcess(process_handle, 1))
13691370
return 0;
13701371

1371-
/* If the process already exited before TerminateProcess was called,.
1372+
/* If the process already exited before TerminateProcess was called,
13721373
* TerminateProcess will fail with ERROR_ACCESS_DENIED. */
13731374
err = GetLastError();
1374-
if (err == ERROR_ACCESS_DENIED &&
1375-
WaitForSingleObject(process_handle, 0) == WAIT_OBJECT_0) {
1376-
return UV_ESRCH;
1375+
if (err == ERROR_ACCESS_DENIED) {
1376+
/* First check using GetExitCodeProcess() with status different from
1377+
* STILL_ACTIVE (259). This check can be set incorrectly by the process,
1378+
* though that is uncommon. */
1379+
if (GetExitCodeProcess(process_handle, &status) &&
1380+
status != STILL_ACTIVE) {
1381+
return UV_ESRCH;
1382+
}
1383+
1384+
/* But the process could have exited with code == STILL_ACTIVE, use then
1385+
* WaitForSingleObject with timeout zero. This is prone to a race
1386+
* condition as it could return WAIT_TIMEOUT because the handle might
1387+
* not have been signaled yet.That would result in returning the wrong
1388+
* error code here (UV_EACCES instead of UV_ESRCH), but we cannot fix
1389+
* the kernel synchronization issue that TerminateProcess is
1390+
* inconsistent with WaitForSingleObject with just the APIs available to
1391+
* us in user space. */
1392+
if (WaitForSingleObject(process_handle, 0) == WAIT_OBJECT_0) {
1393+
return UV_ESRCH;
1394+
}
13771395
}
13781396

13791397
return uv_translate_sys_error(err);
13801398
}
13811399

13821400
case 0: {
13831401
/* Health check: is the process still alive? */
1402+
DWORD status;
1403+
1404+
if (!GetExitCodeProcess(process_handle, &status))
1405+
return uv_translate_sys_error(GetLastError());
1406+
1407+
if (status != STILL_ACTIVE)
1408+
return UV_ESRCH;
1409+
13841410
switch (WaitForSingleObject(process_handle, 0)) {
13851411
case WAIT_OBJECT_0:
13861412
return UV_ESRCH;

0 commit comments

Comments
 (0)