diff --git a/src/ffi/data.cc b/src/ffi/data.cc index cd2a2481ef6e..ca3315d43a35 100644 --- a/src/ffi/data.cc +++ b/src/ffi/data.cc @@ -15,6 +15,8 @@ using v8::ArrayBuffer; using v8::ArrayBufferView; using v8::BackingStore; +using v8::BackingStoreInitializationMode; +using v8::BackingStoreOnFailureMode; using v8::BigInt; using v8::FunctionCallbackInfo; using v8::Integer; @@ -670,8 +672,15 @@ void ToArrayBuffer(const FunctionCallbackInfo& args) { Local ab; if (copy) { - std::unique_ptr store = - ArrayBuffer::NewBackingStore(isolate, len); + std::unique_ptr store = ArrayBuffer::NewBackingStore( + isolate, + len, + BackingStoreInitializationMode::kUninitialized, + BackingStoreOnFailureMode::kReturnNull); + if (!store) [[unlikely]] { + THROW_ERR_MEMORY_ALLOCATION_FAILED(env); + return; + } if (len > 0) memcpy(store->Data(), reinterpret_cast(ptr), len); ab = ArrayBuffer::New(isolate, std::move(store)); } else { diff --git a/test/ffi/test-ffi-memory.js b/test/ffi/test-ffi-memory.js index be9160337dd0..1ca54ce897cb 100644 --- a/test/ffi/test-ffi-memory.js +++ b/test/ffi/test-ffi-memory.js @@ -371,6 +371,17 @@ test('ffi rejects unsafe integers as an offset or length', () => { })); }); +test('ffi toBuffer and toArrayBuffer throw when the copy cannot be allocated', { + skip: (bufferConstants.MAX_LENGTH < 2 ** 50 && 'requires a 64-bit buffer length limit') || + (common.isASan && 'ASan aborts on huge allocations') || + (common.isAIX && 'huge allocations may succeed on AIX and get the process killed'), +}, () => { + // The allocation fails before the source pointer is read. + const error = { code: 'ERR_MEMORY_ALLOCATION_FAILED' }; + assert.throws(() => ffi.toBuffer(1n, 2 ** 50), error); + assert.throws(() => ffi.toArrayBuffer(1n, 2 ** 50), error); +}); + test('ffi memory helpers reject missing required arguments', () => { const widths = ['Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Float32', 'Float64'];