Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit faaccfb

Browse filesBrowse files
addaleaxaduh95
authored andcommitted
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 <anna@addaleax.net> PR-URL: #62857 Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com>
1 parent fdcd775 commit faaccfb
Copy full SHA for faaccfb

1 file changed

+32-36Lines changed: 32 additions & 36 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/ffi/data.cc‎

Copy file name to clipboardExpand all lines: src/ffi/data.cc
+32-36Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ using v8::MaybeLocal;
2525
using v8::NewStringType;
2626
using v8::Number;
2727
using v8::Object;
28+
using v8::SharedArrayBuffer;
2829
using v8::String;
2930
using v8::Value;
3031

@@ -675,26 +676,17 @@ void ExportBytes(const FunctionCallbackInfo<Value>& args) {
675676
return;
676677
}
677678

678-
const uint8_t* source_data = nullptr;
679-
size_t source_len = 0;
679+
// This needs to be kept alive until the data
680+
// is actually copied.
681+
ArrayBufferViewContents<uint8_t> view;
680682

681-
if (args[0]->IsArrayBuffer()) {
682-
Local<ArrayBuffer> array_buffer = args[0].As<ArrayBuffer>();
683-
std::shared_ptr<BackingStore> store = array_buffer->GetBackingStore();
684-
if (!store) {
685-
THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBuffer backing store");
686-
return;
687-
}
688-
source_data = static_cast<const uint8_t*>(store->Data());
689-
source_len = array_buffer->ByteLength();
690-
} else if (args[0]->IsArrayBufferView()) {
691-
ArrayBufferViewContents<uint8_t> view(args[0]);
683+
if (args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer() ||
684+
args[0]->IsArrayBufferView()) {
685+
view.ReadValue(args[0]);
692686
if (view.WasDetached()) {
693687
THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBufferView backing store");
694688
return;
695689
}
696-
source_data = view.data();
697-
source_len = view.length();
698690
} else {
699691
THROW_ERR_INVALID_ARG_TYPE(
700692
env,
@@ -713,12 +705,12 @@ void ExportBytes(const FunctionCallbackInfo<Value>& args) {
713705
return;
714706
}
715707

716-
if (len < source_len) {
708+
if (len < view.length()) {
717709
THROW_ERR_OUT_OF_RANGE(env, "The length must be >= source byte length");
718710
return;
719711
}
720712

721-
if (ptr == 0 && source_len > 0) {
713+
if (ptr == 0 && view.length() > 0) {
722714
THROW_ERR_FFI_INVALID_POINTER(env,
723715
"Cannot create a buffer from a null pointer");
724716
return;
@@ -733,9 +725,7 @@ void ExportBytes(const FunctionCallbackInfo<Value>& args) {
733725
return;
734726
}
735727

736-
if (source_len > 0) {
737-
std::memcpy(reinterpret_cast<void*>(ptr), source_data, source_len);
738-
}
728+
std::memcpy(reinterpret_cast<void*>(ptr), view.data(), view.length());
739729
}
740730

741731
void GetRawPointer(const FunctionCallbackInfo<Value>& args) {
@@ -752,28 +742,34 @@ void GetRawPointer(const FunctionCallbackInfo<Value>& args) {
752742
}
753743

754744
uintptr_t ptr = 0;
745+
size_t offset = 0;
746+
std::shared_ptr<BackingStore> store;
755747

756748
if (args[0]->IsArrayBuffer()) {
757-
Local<ArrayBuffer> array_buffer = args[0].As<ArrayBuffer>();
758-
std::shared_ptr<BackingStore> store = array_buffer->GetBackingStore();
759-
if (!store) {
760-
THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBuffer backing store");
761-
return;
762-
}
763-
ptr = reinterpret_cast<uintptr_t>(store->Data());
749+
store = args[0].As<ArrayBuffer>()->GetBackingStore();
750+
} else if (args[0]->IsSharedArrayBuffer()) {
751+
store = args[0].As<SharedArrayBuffer>()->GetBackingStore();
764752
} else if (args[0]->IsArrayBufferView()) {
765-
ArrayBufferViewContents<uint8_t> view(args[0]);
766-
if (view.WasDetached()) {
767-
THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBufferView backing store");
768-
return;
769-
}
770-
ptr = reinterpret_cast<uintptr_t>(view.data());
753+
// Access the store here to ensure that it exists. Small typed arrays
754+
// may not have a store until this point and can instead be stored
755+
// entirely in-heap.
756+
store = args[0].As<ArrayBufferView>()->Buffer()->GetBackingStore();
757+
offset = args[0].As<ArrayBufferView>()->ByteOffset();
771758
} else {
772-
THROW_ERR_INVALID_ARG_TYPE(
773-
env,
774-
"The first argument must be a Buffer, ArrayBuffer, or ArrayBufferView");
759+
THROW_ERR_INVALID_ARG_TYPE(env,
760+
"The first argument must be a Buffer, "
761+
"ArrayBuffer, or ArrayBufferView");
762+
return;
763+
}
764+
765+
// WARNING: There is no inherent guarantee that the pointer returned
766+
// from this function will be valid beyond the lifetime of the BackingStore
767+
// instance!
768+
if (!store) {
769+
THROW_ERR_INVALID_ARG_VALUE(env, "Invalid ArrayBuffer backing store");
775770
return;
776771
}
772+
ptr = reinterpret_cast<uintptr_t>(store->Data()) + offset;
777773

778774
args.GetReturnValue().Set(
779775
BigInt::NewFromUnsigned(isolate, static_cast<uint64_t>(ptr)));

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.