fix: javascript heap OOM is not raised (#45895)

fix: javascript heap oom is not raised in node::OOMErrorHandler

node::OOMErrorHandler terminates the process directly without raising an
oom exception. To fix it, set an oom handler into node from electron.
This commit is contained in:
yangllu 2025-03-07 00:34:19 +08:00 committed by GitHub
parent 431a791a99
commit d987bee007
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 72 additions and 0 deletions

View file

@ -44,3 +44,4 @@ test_make_eval_snapshot_tests_more_flexible.patch
build_option_to_use_custom_inspector_protocol_path.patch build_option_to_use_custom_inspector_protocol_path.patch
fix_adjust_wpt_and_webidl_tests_for_enabled_float16array.patch fix_adjust_wpt_and_webidl_tests_for_enabled_float16array.patch
chore_add_createexternalizabletwobytestring_to_globals.patch chore_add_createexternalizabletwobytestring_to_globals.patch
feat_add_oom_error_callback_in_node_isolatesettings.patch

View file

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Yang Liu <ouyangliu.leo@gmail.com>
Date: Wed, 5 Mar 2025 17:22:39 +0800
Subject: feat: add oom_error_callback in node::IsolateSettings
Expose v8::OOMErrorCallback to allow setting OOM error handler outside Node.js
As described in this issue https://github.com/electron/electron/issues/45894,
Electron fails to capture js heap oom because node::OOMErrorHandler just
terminates the process without raising an exception.
To fix this issue, provide the interface oom_error_callback to enable a
custom oom error callback set from Electron.
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 32fc075e97eebca6c47e796ac5308915746ffa2a..e72bee385865c7d34e9eea6b90c6d911d592f8af 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -241,7 +241,10 @@ void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
auto* fatal_error_cb = s.fatal_error_callback ?
s.fatal_error_callback : OnFatalError;
isolate->SetFatalErrorHandler(fatal_error_cb);
- isolate->SetOOMErrorHandler(OOMErrorHandler);
+
+ auto* oom_error_cb = s.oom_error_callback ?
+ s.oom_error_callback : OOMErrorHandler;
+ isolate->SetOOMErrorHandler(oom_error_cb);
if ((s.flags & SHOULD_NOT_SET_PREPARE_STACK_TRACE_CALLBACK) == 0) {
auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
diff --git a/src/node.h b/src/node.h
index afb26ec5690ccd65a3c36f8b8a1b2de416b9d843..98ad0ea649eaef43d1f5231f7bc4044e100e08d7 100644
--- a/src/node.h
+++ b/src/node.h
@@ -489,6 +489,7 @@ struct IsolateSettings {
v8::Isolate::AbortOnUncaughtExceptionCallback
should_abort_on_uncaught_exception_callback = nullptr;
v8::FatalErrorCallback fatal_error_callback = nullptr;
+ v8::OOMErrorCallback oom_error_callback = nullptr;
v8::PrepareStackTraceCallback prepare_stack_trace_callback = nullptr;
// Miscellaneous callbacks

View file

@ -10,6 +10,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "base/allocator/partition_allocator/src/partition_alloc/oom.h"
#include "base/base_paths.h" #include "base/base_paths.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/containers/fixed_flat_set.h" #include "base/containers/fixed_flat_set.h"
@ -169,6 +170,33 @@ void V8FatalErrorCallback(const char* location, const char* message) {
*zero = 0; *zero = 0;
} }
void V8OOMErrorCallback(const char* location, const v8::OOMDetails& details) {
const char* message =
details.is_heap_oom ? "Allocation failed - JavaScript heap out of memory"
: "Allocation failed - process out of memory";
if (location) {
LOG(ERROR) << "OOM error in V8: " << location << " " << message;
} else {
LOG(ERROR) << "OOM error in V8: " << message;
}
if (details.detail) {
LOG(ERROR) << "OOM detail: " << details.detail;
}
#if !IS_MAS_BUILD()
electron::crash_keys::SetCrashKey("electron.v8-oom.is_heap_oom",
std::to_string(details.is_heap_oom));
if (location) {
electron::crash_keys::SetCrashKey("electron.v8-oom.location", location);
}
if (details.detail) {
electron::crash_keys::SetCrashKey("electron.v8-oom.detail", details.detail);
}
#endif
OOM_CRASH(0);
}
bool AllowWasmCodeGenerationCallback(v8::Local<v8::Context> context, bool AllowWasmCodeGenerationCallback(v8::Local<v8::Context> context,
v8::Local<v8::String> source) { v8::Local<v8::String> source) {
// If we're running with contextIsolation enabled in the renderer process, // If we're running with contextIsolation enabled in the renderer process,
@ -688,6 +716,7 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
// Use a custom fatal error callback to allow us to add // Use a custom fatal error callback to allow us to add
// crash message and location to CrashReports. // crash message and location to CrashReports.
is.fatal_error_callback = V8FatalErrorCallback; is.fatal_error_callback = V8FatalErrorCallback;
is.oom_error_callback = V8OOMErrorCallback;
// We don't want to abort either in the renderer or browser processes. // We don't want to abort either in the renderer or browser processes.
// We already listen for uncaught exceptions and handle them there. // We already listen for uncaught exceptions and handle them there.