Skip to content

Commit 8909c74

Browse files
bitpshraduh95
authored andcommitted
src: disable V8 external memory reasonable size check
V8 aborts the process when external memory grows by more than --external-memory-max-reasonable-size gigabytes in a single step. The 32 GB default is a Chromium-oriented sanity check; allocating a buffer larger than that is legitimate in Node and should raise a RangeError rather than terminate the process. Default the flag to 0 unless the user supplied a value, alongside the other V8 defaults Node sets explicitly. Fixes: #65534 Signed-off-by: Paul Bouchon <mail@bitpshr.net> PR-URL: #65589 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: René <contact.9a5d6388@renegade334.me.uk> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 6aedc56 commit 8909c74

2 files changed

Lines changed: 47 additions & 0 deletions

File tree

src/node.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,20 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args,
784784
v8_args.emplace_back("--js-source-phase-imports");
785785
}
786786

787+
// V8 aborts the process when external memory grows by more than
788+
// --external-memory-max-reasonable-size gigabytes in a single step. That
789+
// limit is a Chromium-oriented sanity check; allocating a buffer larger
790+
// than it is a legitimate thing to do in Node, and should raise a
791+
// RangeError rather than crash. Disable the check unless the user asked
792+
// for a specific limit.
793+
// Refs: https://github.com/nodejs/node/issues/65534
794+
if (std::ranges::none_of(v8_args, [](const std::string& arg) {
795+
return arg.starts_with("--external-memory-max-reasonable-size") ||
796+
arg.starts_with("--external_memory_max_reasonable_size");
797+
})) {
798+
v8_args.emplace_back("--external-memory-max-reasonable-size=0");
799+
}
800+
787801
#ifdef __POSIX__
788802
// Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the
789803
// performance penalty of frequent EINTR wakeups when the profiler is running.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
// V8 aborts the process when external memory grows by more than
4+
// --external-memory-max-reasonable-size gigabytes in a single step. Node
5+
// disables that check by default, but an explicit value on the command line
6+
// must still be honored.
7+
// Refs: https://github.com/nodejs/node/issues/65534
8+
9+
const common = require('../common');
10+
const assert = require('assert');
11+
const { spawnSync } = require('child_process');
12+
const { totalmem } = require('os');
13+
14+
// The smallest limit V8 accepts is 1 GB, so the child has to allocate more
15+
// than that before the check can fire.
16+
if (totalmem() < 4 * 1024 ** 3)
17+
common.skip('not enough memory to exceed a 1 GB external memory limit');
18+
19+
for (const flag of [
20+
'--external-memory-max-reasonable-size=1',
21+
'--external_memory_max_reasonable_size=1',
22+
]) {
23+
const child = spawnSync(process.execPath, [
24+
flag, '-e', 'new Float64Array(150_000_000)',
25+
]);
26+
27+
assert.notStrictEqual(
28+
child.status,
29+
0,
30+
`${flag} was not honored, the child exited cleanly`,
31+
);
32+
assert.match(child.stderr.toString(), /kMaxReasonableBytes/);
33+
}

0 commit comments

Comments
 (0)