Skip to content

Commit a05e7ef

Browse files
committed
ffi: throw on allocation failure in toArrayBuffer()
The copy path of toArrayBuffer() allocated its backing store with V8's default failure mode, so a large length aborted the process with a fatal out-of-memory error. toBuffer() throws a catchable ERR_MEMORY_ALLOCATION_FAILED for the same input. Allocate with kReturnNull and throw ERR_MEMORY_ALLOCATION_FAILED when the allocation fails. The memory is left uninitialized because memcpy() fills it right after. Signed-off-by: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Assisted-by: claude:opus-5.5
1 parent f71d644 commit a05e7ef

2 files changed

Lines changed: 21 additions & 2 deletions

File tree

‎src/ffi/data.cc‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
using v8::ArrayBuffer;
1616
using v8::ArrayBufferView;
1717
using v8::BackingStore;
18+
using v8::BackingStoreInitializationMode;
19+
using v8::BackingStoreOnFailureMode;
1820
using v8::BigInt;
1921
using v8::FunctionCallbackInfo;
2022
using v8::Integer;
@@ -667,8 +669,15 @@ void ToArrayBuffer(const FunctionCallbackInfo<Value>& args) {
667669

668670
Local<ArrayBuffer> ab;
669671
if (copy) {
670-
std::unique_ptr<BackingStore> store =
671-
ArrayBuffer::NewBackingStore(isolate, len);
672+
std::unique_ptr<BackingStore> store = ArrayBuffer::NewBackingStore(
673+
isolate,
674+
len,
675+
BackingStoreInitializationMode::kUninitialized,
676+
BackingStoreOnFailureMode::kReturnNull);
677+
if (!store) [[unlikely]] {
678+
THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
679+
return;
680+
}
672681
if (len > 0) memcpy(store->Data(), reinterpret_cast<void*>(ptr), len);
673682
ab = ArrayBuffer::New(isolate, std::move(store));
674683
} else {

‎test/ffi/test-ffi-memory.js‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,16 @@ test('ffi validates memory access arguments', () => {
351351
}));
352352
});
353353

354+
test('ffi toBuffer and toArrayBuffer throw when the copy cannot be allocated', {
355+
skip: (bufferConstants.MAX_LENGTH < 2 ** 50 && 'requires a 64-bit buffer length limit') ||
356+
(common.isASan && 'ASan aborts on huge allocations'),
357+
}, () => {
358+
// The allocation fails before the source pointer is read.
359+
const error = { code: 'ERR_MEMORY_ALLOCATION_FAILED' };
360+
assert.throws(() => ffi.toBuffer(1n, 2 ** 50), error);
361+
assert.throws(() => ffi.toArrayBuffer(1n, 2 ** 50), error);
362+
});
363+
354364
test('ffi memory helpers reject missing required arguments', () => {
355365
const widths = ['Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32',
356366
'Int64', 'Uint64', 'Float32', 'Float64'];

0 commit comments

Comments
 (0)