Summary
On Windows, ServerApplication::hasConsole() only checks GetStdHandle(STD_OUTPUT_HANDLE). When a child process is launched with PROCESS_CLOSE_STDOUT (e.g., via ProcessRunner with NO_OUT option), stdout is NULL even though the process has a valid console window and stdin handle. This causes hasConsole() to return false, which triggers isService() to call StartServiceCtrlDispatcherW(), blocking indefinitely for a non-service process.
Reproduction
- Launch a
ServerApplication-based process using ProcessRunner with the default NO_OUT option (PROCESS_CLOSE_STDOUT | PROCESS_CLOSE_STDERR)
- The child process has
consoleWindow=YES, stdin=YES, stdout=NULL, stderr=NULL
hasConsole() returns false because it only checks stdout
isService() calls StartServiceCtrlDispatcherW() which blocks
- The process never reaches
main()
Root cause
In Util/src/ServerApplication.cpp:
bool ServerApplication::hasConsole()
{
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
return hStdOut != INVALID_HANDLE_VALUE && hStdOut != NULL;
}
This only checks stdout. When the parent launches the child with PROCESS_CLOSE_STDOUT, the child's stdout is NULL, but the process still has a valid console (inherited from the parent).
Fix
Check GetConsoleWindow() first (definitive proof of a console), then fall back to checking all three standard handles:
bool ServerApplication::hasConsole()
{
if (GetConsoleWindow() != NULL) return true;
HANDLE handles[] = {
GetStdHandle(STD_OUTPUT_HANDLE),
GetStdHandle(STD_INPUT_HANDLE),
GetStdHandle(STD_ERROR_HANDLE)
};
for (HANDLE h : handles)
{
if (h != INVALID_HANDLE_VALUE && h != NULL)
return true;
}
return false;
}
Affected files
platform/Util/src/ServerApplication.cpp - hasConsole() method
Summary
On Windows,
ServerApplication::hasConsole()only checksGetStdHandle(STD_OUTPUT_HANDLE). When a child process is launched withPROCESS_CLOSE_STDOUT(e.g., viaProcessRunnerwithNO_OUToption), stdout is NULL even though the process has a valid console window and stdin handle. This causeshasConsole()to return false, which triggersisService()to callStartServiceCtrlDispatcherW(), blocking indefinitely for a non-service process.Reproduction
ServerApplication-based process usingProcessRunnerwith the defaultNO_OUToption (PROCESS_CLOSE_STDOUT | PROCESS_CLOSE_STDERR)consoleWindow=YES,stdin=YES,stdout=NULL,stderr=NULLhasConsole()returns false because it only checks stdoutisService()callsStartServiceCtrlDispatcherW()which blocksmain()Root cause
In
Util/src/ServerApplication.cpp:This only checks stdout. When the parent launches the child with
PROCESS_CLOSE_STDOUT, the child's stdout is NULL, but the process still has a valid console (inherited from the parent).Fix
Check
GetConsoleWindow()first (definitive proof of a console), then fall back to checking all three standard handles:Affected files
platform/Util/src/ServerApplication.cpp-hasConsole()method