From 9326d896daf8834bea3785151d368f564fb30f18 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Thu, 22 Jan 2026 15:01:27 -0500 Subject: [PATCH] src: throw RangeError on failed ArrayBuffer BackingStore allocation This also updates `ERR_MEMORY_ALLOCATION_FAILED` to be a RangeError, aligning with V8's OutOfMemory error type. --- src/encoding_binding.cc | 11 ++++++++-- src/node_blob.cc | 10 ++++++++- src/node_buffer.cc | 45 +++++++++++++++++++++++++++++++---------- src/node_errors.h | 2 +- 4 files changed, 53 insertions(+), 15 deletions(-) diff --git a/src/encoding_binding.cc b/src/encoding_binding.cc index 7683d205aa6a3e..aa901350180b3c 100644 --- a/src/encoding_binding.cc +++ b/src/encoding_binding.cc @@ -17,6 +17,7 @@ namespace encoding_binding { using v8::ArrayBuffer; using v8::BackingStore; using v8::BackingStoreInitializationMode; +using v8::BackingStoreOnFailureMode; using v8::Context; using v8::FunctionCallbackInfo; using v8::HandleScope; @@ -317,9 +318,15 @@ void BindingData::EncodeUtf8String(const FunctionCallbackInfo& args) { Local ab; { std::unique_ptr bs = ArrayBuffer::NewBackingStore( - isolate, length, BackingStoreInitializationMode::kUninitialized); + isolate, + length, + BackingStoreInitializationMode::kUninitialized, + BackingStoreOnFailureMode::kReturnNull); - CHECK(bs); + if (!bs) [[unlikely]] { + THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate); + return; + } // We are certain that `data` is sufficiently large str->WriteUtf8V2(isolate, diff --git a/src/node_blob.cc b/src/node_blob.cc index ab862bf93a411e..417cd8cbd307b9 100644 --- a/src/node_blob.cc +++ b/src/node_blob.cc @@ -22,6 +22,7 @@ using v8::ArrayBuffer; using v8::ArrayBufferView; using v8::BackingStore; using v8::BackingStoreInitializationMode; +using v8::BackingStoreOnFailureMode; using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; @@ -83,7 +84,14 @@ void Concat(const FunctionCallbackInfo& args) { } std::shared_ptr store = ArrayBuffer::NewBackingStore( - isolate, total, BackingStoreInitializationMode::kUninitialized); + isolate, + total, + BackingStoreInitializationMode::kUninitialized, + BackingStoreOnFailureMode::kReturnNull); + if (!store) [[unlikely]] { + THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate); + return; + } uint8_t* ptr = static_cast(store->Data()); for (size_t n = 0; n < views.size(); n++) { uint8_t* from = diff --git a/src/node_buffer.cc b/src/node_buffer.cc index ddee7b7e40c3ee..e1bee00825d140 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -59,6 +59,7 @@ using v8::ArrayBuffer; using v8::ArrayBufferView; using v8::BackingStore; using v8::BackingStoreInitializationMode; +using v8::BackingStoreOnFailureMode; using v8::CFunction; using v8::Context; using v8::EscapableHandleScope; @@ -304,17 +305,20 @@ MaybeLocal New(Isolate* isolate, EscapableHandleScope scope(isolate); size_t length; - if (!StringBytes::Size(isolate, string, enc).To(&length)) - return Local(); + if (!StringBytes::Size(isolate, string, enc).To(&length)) return {}; size_t actual = 0; std::unique_ptr store; if (length > 0) { - store = ArrayBuffer::NewBackingStore(isolate, length); + store = ArrayBuffer::NewBackingStore( + isolate, + length, + BackingStoreInitializationMode::kZeroInitialized, + BackingStoreOnFailureMode::kReturnNull); if (!store) [[unlikely]] { THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate); - return Local(); + return {}; } actual = StringBytes::Write( @@ -329,7 +333,14 @@ MaybeLocal New(Isolate* isolate, if (actual < length) { std::unique_ptr old_store = std::move(store); store = ArrayBuffer::NewBackingStore( - isolate, actual, BackingStoreInitializationMode::kUninitialized); + isolate, + actual, + BackingStoreInitializationMode::kUninitialized, + BackingStoreOnFailureMode::kReturnNull); + if (!store) [[unlikely]] { + THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate); + return {}; + } memcpy(store->Data(), old_store->Data(), actual); } Local buf = ArrayBuffer::New(isolate, std::move(store)); @@ -372,7 +383,14 @@ MaybeLocal New(Environment* env, size_t length) { Local ab; { std::unique_ptr bs = ArrayBuffer::NewBackingStore( - isolate, length, BackingStoreInitializationMode::kUninitialized); + isolate, + length, + BackingStoreInitializationMode::kUninitialized, + BackingStoreOnFailureMode::kReturnNull); + if (!bs) [[unlikely]] { + THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate); + return {}; + } CHECK(bs); @@ -412,9 +430,14 @@ MaybeLocal Copy(Environment* env, const char* data, size_t length) { } std::unique_ptr bs = ArrayBuffer::NewBackingStore( - isolate, length, BackingStoreInitializationMode::kUninitialized); - - CHECK(bs); + isolate, + length, + BackingStoreInitializationMode::kUninitialized, + BackingStoreOnFailureMode::kReturnNull); + if (!bs) [[unlikely]] { + THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate); + return {}; + } if (length > 0) memcpy(bs->Data(), data, length); @@ -1449,8 +1472,8 @@ void CreateUnsafeArrayBuffer(const FunctionCallbackInfo& args) { BackingStoreInitializationMode::kUninitialized, v8::BackingStoreOnFailureMode::kReturnNull); - if (!store) { - env->ThrowRangeError("Array buffer allocation failed"); + if (!store) [[unlikely]] { + THROW_ERR_MEMORY_ALLOCATION_FAILED(env); return; } diff --git a/src/node_errors.h b/src/node_errors.h index 191374210aae2b..406ad251bcf4bb 100644 --- a/src/node_errors.h +++ b/src/node_errors.h @@ -106,7 +106,7 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details); V(ERR_INVALID_URL_PATTERN, TypeError) \ V(ERR_INVALID_URL_SCHEME, TypeError) \ V(ERR_LOAD_SQLITE_EXTENSION, Error) \ - V(ERR_MEMORY_ALLOCATION_FAILED, Error) \ + V(ERR_MEMORY_ALLOCATION_FAILED, RangeError) \ V(ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE, Error) \ V(ERR_MISSING_ARGS, TypeError) \ V(ERR_MISSING_PASSPHRASE, TypeError) \