From 147fc504b784af637291104b89df0d59ad65d807 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 20 Apr 2026 17:38:40 +0200 Subject: [PATCH 1/2] src: simplify and fix FFI ArrayBuffer accesses `ArrayBufferViewContents` supports `ArrayBuffer`s, so we do not need to provide special treatment for those. Also, small typed arrays may not have backing stores until their corresponding `ArrayBuffer`s are accessed, so do that in order to avoid accidentally accessing arbitrary stack memory. Signed-off-by: Anna Henningsen --- src/ffi/data.cc | 67 +++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/src/ffi/data.cc b/src/ffi/data.cc index 0d92981bf54ceb..4b035bfb71e933 100644 --- a/src/ffi/data.cc +++ b/src/ffi/data.cc @@ -675,26 +675,17 @@ void ExportBytes(const FunctionCallbackInfo& args) { return; } - const uint8_t* source_data = nullptr; - size_t source_len = 0; + // This needs to be kept alive until the data + // is actually copied. + ArrayBufferViewContents view; - if (args[0]->IsArrayBuffer()) { - Local array_buffer = args[0].As(); - std::shared_ptr store = array_buffer->GetBackingStore(); - if (!store) { - THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBuffer backing store"); - return; - } - source_data = static_cast(store->Data()); - source_len = array_buffer->ByteLength(); - } else if (args[0]->IsArrayBufferView()) { - ArrayBufferViewContents view(args[0]); + if (args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer() || + args[0]->IsArrayBufferView()) { + view.ReadValue(args[0]); if (view.WasDetached()) { THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBufferView backing store"); return; } - source_data = view.data(); - source_len = view.length(); } else { THROW_ERR_INVALID_ARG_TYPE( env, @@ -713,12 +704,12 @@ void ExportBytes(const FunctionCallbackInfo& args) { return; } - if (len < source_len) { + if (len < view.length()) { THROW_ERR_OUT_OF_RANGE(env, "The length must be >= source byte length"); return; } - if (ptr == 0 && source_len > 0) { + if (ptr == 0 && view.length() > 0) { THROW_ERR_FFI_INVALID_POINTER(env, "Cannot create a buffer from a null pointer"); return; @@ -733,9 +724,7 @@ void ExportBytes(const FunctionCallbackInfo& args) { return; } - if (source_len > 0) { - std::memcpy(reinterpret_cast(ptr), source_data, source_len); - } + std::memcpy(reinterpret_cast(ptr), view.data(), view.length()); } void GetRawPointer(const FunctionCallbackInfo& args) { @@ -752,28 +741,34 @@ void GetRawPointer(const FunctionCallbackInfo& args) { } uintptr_t ptr = 0; + size_t offset = 0; + std::shared_ptr store; if (args[0]->IsArrayBuffer()) { - Local array_buffer = args[0].As(); - std::shared_ptr store = array_buffer->GetBackingStore(); - if (!store) { - THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBuffer backing store"); - return; - } - ptr = reinterpret_cast(store->Data()); + store = args[0].As()->GetBackingStore(); + } else if (args[0]->IsSharedArrayBuffer()) { + store = args[0].As()->GetBackingStore(); } else if (args[0]->IsArrayBufferView()) { - ArrayBufferViewContents view(args[0]); - if (view.WasDetached()) { - THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBufferView backing store"); - return; - } - ptr = reinterpret_cast(view.data()); + // Access the store here to ensure that it exists. Small typed arrays + // may not have a store until this point and can instead be stored + // entirely in-heap. + store = args[0].As()->Buffer()->GetBackingStore(); + offset = args[0].As()->ByteOffset(); } else { - THROW_ERR_INVALID_ARG_TYPE( - env, - "The first argument must be a Buffer, ArrayBuffer, or ArrayBufferView"); + THROW_ERR_INVALID_ARG_TYPE(env, + "The first argument must be a Buffer, " + "ArrayBuffer, or ArrayBufferView"); + return; + } + + // WARNING: There is no inherent guarantee that the pointer returned + // from this function will be valid beyond the lifetime of the BackingStore + // instance! + if (!store) { + THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBuffer backing store"); return; } + ptr = reinterpret_cast(store->Data()) + offset; args.GetReturnValue().Set( BigInt::NewFromUnsigned(isolate, static_cast(ptr))); From b6651d87ae5d61ca074264923163e8ab6aff72ed Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 20 Apr 2026 18:54:23 +0200 Subject: [PATCH 2/2] fixup! src: simplify and fix FFI ArrayBuffer accesses --- src/ffi/data.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ffi/data.cc b/src/ffi/data.cc index 4b035bfb71e933..1528d76996a281 100644 --- a/src/ffi/data.cc +++ b/src/ffi/data.cc @@ -25,6 +25,7 @@ using v8::MaybeLocal; using v8::NewStringType; using v8::Number; using v8::Object; +using v8::SharedArrayBuffer; using v8::String; using v8::Value;