Skip to content

Commit 10da0d6

Browse files
trop[bot]yangllu
andauthored
fix: javascript heap OOM is not raised (#45911)
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. Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Yang Liu <[email protected]>
1 parent 463031b commit 10da0d6

File tree

3 files changed

+72
-0
lines changed

3 files changed

+72
-0
lines changed

patches/node/.patches

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ linux_try_preadv64_pwritev64_before_preadv_pwritev_4683.patch
4444
build_change_crdtp_protocoltypetraits_signatures_to_avoid_conflict.patch
4545
test_make_eval_snapshot_tests_more_flexible.patch
4646
build_option_to_use_custom_inspector_protocol_path.patch
47+
feat_add_oom_error_callback_in_node_isolatesettings.patch
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: Yang Liu <[email protected]>
3+
Date: Wed, 5 Mar 2025 17:22:39 +0800
4+
Subject: feat: add oom_error_callback in node::IsolateSettings
5+
6+
Expose v8::OOMErrorCallback to allow setting OOM error handler outside Node.js
7+
8+
As described in this issue https://github.com/electron/electron/issues/45894,
9+
Electron fails to capture js heap oom because node::OOMErrorHandler just
10+
terminates the process without raising an exception.
11+
12+
To fix this issue, provide the interface oom_error_callback to enable a
13+
custom oom error callback set from Electron.
14+
15+
diff --git a/src/api/environment.cc b/src/api/environment.cc
16+
index 32fc075e97eebca6c47e796ac5308915746ffa2a..e72bee385865c7d34e9eea6b90c6d911d592f8af 100644
17+
--- a/src/api/environment.cc
18+
+++ b/src/api/environment.cc
19+
@@ -241,7 +241,10 @@ void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
20+
auto* fatal_error_cb = s.fatal_error_callback ?
21+
s.fatal_error_callback : OnFatalError;
22+
isolate->SetFatalErrorHandler(fatal_error_cb);
23+
- isolate->SetOOMErrorHandler(OOMErrorHandler);
24+
+
25+
+ auto* oom_error_cb = s.oom_error_callback ?
26+
+ s.oom_error_callback : OOMErrorHandler;
27+
+ isolate->SetOOMErrorHandler(oom_error_cb);
28+
29+
if ((s.flags & SHOULD_NOT_SET_PREPARE_STACK_TRACE_CALLBACK) == 0) {
30+
auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
31+
diff --git a/src/node.h b/src/node.h
32+
index afb26ec5690ccd65a3c36f8b8a1b2de416b9d843..98ad0ea649eaef43d1f5231f7bc4044e100e08d7 100644
33+
--- a/src/node.h
34+
+++ b/src/node.h
35+
@@ -489,6 +489,7 @@ struct IsolateSettings {
36+
v8::Isolate::AbortOnUncaughtExceptionCallback
37+
should_abort_on_uncaught_exception_callback = nullptr;
38+
v8::FatalErrorCallback fatal_error_callback = nullptr;
39+
+ v8::OOMErrorCallback oom_error_callback = nullptr;
40+
v8::PrepareStackTraceCallback prepare_stack_trace_callback = nullptr;
41+
42+
// Miscellaneous callbacks

shell/common/node_bindings.cc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <utility>
1111
#include <vector>
1212

13+
#include "base/allocator/partition_allocator/src/partition_alloc/oom.h"
1314
#include "base/base_paths.h"
1415
#include "base/command_line.h"
1516
#include "base/containers/fixed_flat_set.h"
@@ -169,6 +170,33 @@ void V8FatalErrorCallback(const char* location, const char* message) {
169170
*zero = 0;
170171
}
171172

173+
void V8OOMErrorCallback(const char* location, const v8::OOMDetails& details) {
174+
const char* message =
175+
details.is_heap_oom ? "Allocation failed - JavaScript heap out of memory"
176+
: "Allocation failed - process out of memory";
177+
if (location) {
178+
LOG(ERROR) << "OOM error in V8: " << location << " " << message;
179+
} else {
180+
LOG(ERROR) << "OOM error in V8: " << message;
181+
}
182+
if (details.detail) {
183+
LOG(ERROR) << "OOM detail: " << details.detail;
184+
}
185+
186+
#if !IS_MAS_BUILD()
187+
electron::crash_keys::SetCrashKey("electron.v8-oom.is_heap_oom",
188+
std::to_string(details.is_heap_oom));
189+
if (location) {
190+
electron::crash_keys::SetCrashKey("electron.v8-oom.location", location);
191+
}
192+
if (details.detail) {
193+
electron::crash_keys::SetCrashKey("electron.v8-oom.detail", details.detail);
194+
}
195+
#endif
196+
197+
OOM_CRASH(0);
198+
}
199+
172200
bool AllowWasmCodeGenerationCallback(v8::Local<v8::Context> context,
173201
v8::Local<v8::String> source) {
174202
// If we're running with contextIsolation enabled in the renderer process,
@@ -688,6 +716,7 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
688716
// Use a custom fatal error callback to allow us to add
689717
// crash message and location to CrashReports.
690718
is.fatal_error_callback = V8FatalErrorCallback;
719+
is.oom_error_callback = V8OOMErrorCallback;
691720

692721
// We don't want to abort either in the renderer or browser processes.
693722
// We already listen for uncaught exceptions and handle them there.

0 commit comments

Comments
 (0)