Skip to content

Commit 54907ac

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 bd83a5c commit 54907ac

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;
@@ -670,8 +672,15 @@ void ToArrayBuffer(const FunctionCallbackInfo<Value>& args) {
670672

671673
Local<ArrayBuffer> ab;
672674
if (copy) {
673-
std::unique_ptr<BackingStore> store =
674-
ArrayBuffer::NewBackingStore(isolate, len);
675+
std::unique_ptr<BackingStore> store = ArrayBuffer::NewBackingStore(
676+
isolate,
677+
len,
678+
BackingStoreInitializationMode::kUninitialized,
679+
BackingStoreOnFailureMode::kReturnNull);
680+
if (!store) [[unlikely]] {
681+
THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
682+
return;
683+
}
675684
if (len > 0) memcpy(store->Data(), reinterpret_cast<void*>(ptr), len);
676685
ab = ArrayBuffer::New(isolate, std::move(store));
677686
} else {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,16 @@ test('ffi rejects unsafe integers as an offset or length', () => {
371371
}));
372372
});
373373

374+
test('ffi toBuffer and toArrayBuffer throw when the copy cannot be allocated', {
375+
skip: (bufferConstants.MAX_LENGTH < 2 ** 50 && 'requires a 64-bit buffer length limit') ||
376+
(common.isASan && 'ASan aborts on huge allocations'),
377+
}, () => {
378+
// The allocation fails before the source pointer is read.
379+
const error = { code: 'ERR_MEMORY_ALLOCATION_FAILED' };
380+
assert.throws(() => ffi.toBuffer(1n, 2 ** 50), error);
381+
assert.throws(() => ffi.toArrayBuffer(1n, 2 ** 50), error);
382+
});
383+
374384
test('ffi memory helpers reject missing required arguments', () => {
375385
const widths = ['Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32',
376386
'Int64', 'Uint64', 'Float32', 'Float64'];

0 commit comments

Comments
 (0)