Skip to content

Commit

Permalink
win: prevent tty event explosion machine hang
Browse files Browse the repository at this point in the history
The tty subsystem on Windows was listening for console events from all
processes to detect when our console window was being resized. This
could cause an explosion in the number of events queued by the system
when running many console applications in parallel that all wrote to
their console quickly. The end result was a complete machine hang.

Now we determine, whenever possible, what our corresponding conhost.exe
process is and listen for console events from that process only. This
detection does not work in 32-bit applications running on 64-bit
Windows so those default to the old behavior of listening to all
processes.

PR-URL: libuv#2308
Reviewed-By: Saúl Ibarra Corretgé <[email protected]>
Reviewed-By: Bartosz Sosnowski <[email protected]>
  • Loading branch information
jblazquez authored and bzoz committed Jul 12, 2019
1 parent a5d3743 commit dabc737
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 2 deletions.
21 changes: 19 additions & 2 deletions src/win/tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -2280,6 +2280,8 @@ static void uv__determine_vterm_state(HANDLE handle) {

static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
CONSOLE_SCREEN_BUFFER_INFO sb_info;
NTSTATUS status;
ULONG_PTR conhost_pid;
MSG msg;

if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
Expand All @@ -2288,14 +2290,29 @@ static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
uv__tty_console_width = sb_info.dwSize.X;
uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;

if (pSetWinEventHook == NULL)
if (pSetWinEventHook == NULL || pNtQueryInformationProcess == NULL)
return 0;

status = pNtQueryInformationProcess(GetCurrentProcess(),
ProcessConsoleHostProcess,
&conhost_pid,
sizeof(conhost_pid),
NULL);

if (!NT_SUCCESS(status))
/* We couldn't retrieve our console host process, probably because this
* is a 32-bit process running on 64-bit Windows. Fall back to receiving
* console events from all processes. */
conhost_pid = 0;

/* Ensure the PID is a multiple of 4, which is required by SetWinEventHook */
conhost_pid &= ~(ULONG_PTR)0x3;

if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
EVENT_CONSOLE_LAYOUT,
NULL,
uv__tty_console_resize_event,
0,
(DWORD)conhost_pid,
0,
WINEVENT_OUTOFCONTEXT))
return 0;
Expand Down
8 changes: 8 additions & 0 deletions src/win/winapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ sNtSetInformationFile pNtSetInformationFile;
sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
sNtQueryDirectoryFile pNtQueryDirectoryFile;
sNtQuerySystemInformation pNtQuerySystemInformation;
sNtQueryInformationProcess pNtQueryInformationProcess;

/* Kernel32 function pointers */
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
Expand Down Expand Up @@ -106,6 +107,13 @@ void uv_winapi_init(void) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}

pNtQueryInformationProcess = (sNtQueryInformationProcess) GetProcAddress(
ntdll_module,
"NtQueryInformationProcess");
if (pNtQueryInformationProcess == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}

kernel32_module = GetModuleHandleA("kernel32.dll");
if (kernel32_module == NULL) {
uv_fatal_error(GetLastError(), "GetModuleHandleA");
Expand Down
12 changes: 12 additions & 0 deletions src/win/winapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -4436,6 +4436,10 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
# define SystemProcessorPerformanceInformation 8
#endif

#ifndef ProcessConsoleHostProcess
# define ProcessConsoleHostProcess 49
#endif

#ifndef FILE_DEVICE_FILE_SYSTEM
# define FILE_DEVICE_FILE_SYSTEM 0x00000009
#endif
Expand Down Expand Up @@ -4578,6 +4582,13 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
BOOLEAN RestartScan
);

typedef NTSTATUS (NTAPI *sNtQueryInformationProcess)
(HANDLE ProcessHandle,
UINT ProcessInformationClass,
PVOID ProcessInformation,
ULONG Length,
PULONG ReturnLength);

/*
* Kernel32 headers
*/
Expand Down Expand Up @@ -4718,6 +4729,7 @@ extern sNtSetInformationFile pNtSetInformationFile;
extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
extern sNtQuerySystemInformation pNtQuerySystemInformation;
extern sNtQueryInformationProcess pNtQueryInformationProcess;

/* Kernel32 function pointers */
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
Expand Down

0 comments on commit dabc737

Please sign in to comment.