fix: automatically skip stdio initialization when NUL is unavailable (#53459)

Automatically set kNoStdioInitialization on Windows when the NUL device
cannot be opened, rather than aborting startup. Apply this to both
embedded Node.js and ELECTRON_RUN_AS_NODE initialization.

Remove the --no-stdio-init switch and its child-process forwarding, and
update the command-line and breaking changes documentation. Preserve
normal stdio initialization when NUL is available and on other platforms.

Closes #52677

Assisted-By: GPT 6.1 Sol
This commit is contained in:
Zhong Lufan (钟路帆) authored and GitHub committed 2026-10-26 11:46:29 -04:00
1 parent e9bc0b2292
commit baf7eaf5b4
6 files changed
+20 -37

No files matched your search

-5
View File
@@ -197,11 +197,6 @@ Disables the Chromium [sandbox](https://www.chromium.org/developers/design-docum
Forces renderer process and Chromium helper processes to run un-sandboxed.
Should only be used for testing.
### --no-stdio-init
Disable stdio initialization during node initialization.
Used to avoid node initialization crash when the nul device is disabled on Windows platform.
### --ozone-platform=`platform` _Linux_
Forces Electron to use a specific display backend instead of choosing one
+12
View File
@@ -16,6 +16,18 @@ This document uses the following convention to categorize breaking changes:
## Breaking API Changes (46.0)
### Removed: `--no-stdio-init` command-line switch
The `--no-stdio-init` command-line switch has been removed.
On Windows, Electron now automatically skips Node.js stdio initialization when
the `NUL` device cannot be opened, instead of aborting startup. This applies to
both regular Electron processes and `ELECTRON_RUN_AS_NODE` mode. Stdio
initialization remains enabled when `NUL` is available.
Remove this switch from application launch arguments. No replacement is needed
for the Windows `NUL` device workaround.
### Behavior Changed: `utilityProcess` `child.kill()` no longer force-kills the child
`child.kill()` used to send `SIGTERM` and then `SIGKILL` two seconds later if the
+4 -15
View File
@@ -33,7 +33,6 @@
#include "shell/common/node_bindings.h"
#include "shell/common/node_includes.h"
#include "shell/common/node_util.h"
#include "shell/common/options_switches.h"
#include "shell/common/platform_util.h"
#include "third_party/electron_node/src/tracing/agent.h"
@@ -161,9 +160,8 @@ int NodeMain() {
v8_crashpad_support::SetUp();
#endif
auto* command_line = base::CommandLine::ForCurrentProcess();
#if BUILDFLAG(IS_LINUX)
auto* command_line = base::CommandLine::ForCurrentProcess();
int pid = -1;
std::optional<std::string> fd_string = os_env->GetVar("CRASHDUMP_SIGNAL_FD");
std::optional<std::string> pid_string =
@@ -211,20 +209,11 @@ int NodeMain() {
node::ProcessInitializationFlags::kNoInitializeV8 |
node::ProcessInitializationFlags::kNoInitializeNodeV8Platform;
if (command_line->HasSwitch(switches::kNoStdioInit)) {
process_flags |= node::ProcessInitializationFlags::kNoStdioInitialization;
// remove the option to avoid node error "bad option: --no-stdio-init"
std::string option = std::string("--") + switches::kNoStdioInit;
std::erase(args, option);
} else {
#if BUILDFLAG(IS_WIN)
if (!platform_util::IsNulDeviceEnabled()) {
LOG(FATAL) << "Unable to open nul device needed for initialization,"
"aborting startup. As a workaround, try starting with --"
<< switches::kNoStdioInit;
}
// Node.js aborts when it cannot replace missing stdio handles with NUL.
if (!platform_util::IsNulDeviceEnabled())
process_flags |= node::ProcessInitializationFlags::kNoStdioInitialization;
#endif
}
std::shared_ptr<node::InitializationResult> result =
node::InitializeOncePerProcess(
+1 -2
View File
@@ -644,7 +644,7 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches(
if (process_type == ::switches::kUtilityProcess ||
process_type == ::switches::kRendererProcess) {
// Copy following switches to child process.
static constexpr std::array<const char*, 11U> kCommonSwitchNames = {
static constexpr std::array<const char*, 10U> kCommonSwitchNames = {
switches::kStandardSchemes.c_str(),
switches::kEnableSandbox.c_str(),
switches::kSecureSchemes.c_str(),
@@ -653,7 +653,6 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches(
switches::kFetchSchemes.c_str(),
switches::kServiceWorkerSchemes.c_str(),
switches::kStreamingSchemes.c_str(),
switches::kNoStdioInit.c_str(),
switches::kCodeCacheSchemes.c_str(),
switches::kExtensionSchemes.c_str()};
command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
+3 -11
View File
@@ -45,7 +45,6 @@
#include "shell/common/mac/main_application_bundle.h"
#include "shell/common/node_includes.h"
#include "shell/common/node_util.h"
#include "shell/common/options_switches.h"
#include "shell/common/platform_util.h"
#include "shell/common/process_util.h"
#include "shell/common/world_ids.h"
@@ -733,18 +732,11 @@ void NodeBindings::Initialize(v8::Isolate* const isolate,
if (!fuses::IsNodeOptionsEnabled())
process_flags |= node::ProcessInitializationFlags::kDisableNodeOptionsEnv;
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kNoStdioInit)) {
process_flags |= node::ProcessInitializationFlags::kNoStdioInitialization;
} else {
#if BUILDFLAG(IS_WIN)
if (!platform_util::IsNulDeviceEnabled()) {
LOG(FATAL) << "Unable to open nul device needed for initialization,"
"aborting startup. As a workaround, try starting with --"
<< switches::kNoStdioInit;
}
// Node.js aborts when it cannot replace missing stdio handles with NUL.
if (!platform_util::IsNulDeviceEnabled())
process_flags |= node::ProcessInitializationFlags::kNoStdioInitialization;
#endif
}
std::shared_ptr<node::InitializationResult> result =
node::InitializeOncePerProcess(
-4
View File
@@ -331,10 +331,6 @@ inline constexpr base::cstring_view kEnableAuthNegotiatePort =
// If set, NTLM v2 is disabled for POSIX platforms.
inline constexpr base::cstring_view kDisableNTLMv2 = "disable-ntlm-v2";
// If set, flag node::ProcessInitializationFlags::kNoStdioInitialization would
// be set for node initialization.
inline constexpr base::cstring_view kNoStdioInit = "no-stdio-init";
} // namespace switches
} // namespace electron