Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ArrayBuffer::set_detach_key #1127

Merged
merged 1 commit into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add ArrayBuffer::set_detach_key
This method, introduced in V8 10.9, makes it so an `ArrayBuffer`
object is impossible to detach unless a specific detach key is passed
to the `detach` method. Such `ArrayBuffer`s still count as detachable
as per the `ArrayBuffer::is_detachable` method, but otherwise behave
much like WebAssembly memories.
  • Loading branch information
andreubotella committed Nov 21, 2022
commit d62d84b8906586af6f12424a69e31e4c4c23a63d
9 changes: 8 additions & 1 deletion src/array_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ extern "C" {
this: *const ArrayBuffer,
key: *const Value,
) -> MaybeBool;
fn v8__ArrayBuffer__SetDetachKey(this: *const ArrayBuffer, key: *const Value);
fn v8__ArrayBuffer__Data(this: *const ArrayBuffer) -> *mut c_void;
fn v8__ArrayBuffer__IsDetachable(this: *const ArrayBuffer) -> bool;
fn v8__ArrayBuffer__WasDetached(this: *const ArrayBuffer) -> bool;
Expand Down Expand Up @@ -408,7 +409,7 @@ impl ArrayBuffer {
/// Detaching sets the byte length of the buffer and all typed arrays to zero,
/// preventing JavaScript from ever accessing underlying backing store.
/// ArrayBuffer should have been externalized and must be detachable. Returns
/// `None` if the key didn't pass the [[ArrayBufferDetachKey]] check,
/// `None` if the key didn't pass the `[[ArrayBufferDetachKey]]` check,
/// and `Some(true)` otherwise.
#[inline(always)]
pub fn detach(&self, key: Local<Value>) -> Option<bool> {
Expand All @@ -421,6 +422,12 @@ impl ArrayBuffer {
}
}

/// Sets the `[[ArrayBufferDetachKey]]`.
#[inline(always)]
pub fn set_detach_key(&self, key: Local<Value>) {
unsafe { v8__ArrayBuffer__SetDetachKey(self, &*key) };
}

/// More efficient shortcut for GetBackingStore()->Data().
/// The returned pointer is valid as long as the ArrayBuffer is alive.
#[inline(always)]
Expand Down
5 changes: 5 additions & 0 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,11 @@ bool v8__ArrayBuffer__WasDetached(const v8::ArrayBuffer& self) {
return v8::Utils::OpenHandle(&self)->was_detached();
}

void v8__ArrayBuffer__SetDetachKey(const v8::ArrayBuffer& self,
const v8::Value* key) {
return ptr_to_local(&self)->SetDetachKey(ptr_to_local(key));
}

void* v8__BackingStore__Data(const v8::BackingStore& self) {
return self.Data();
}
Expand Down
47 changes: 47 additions & 0 deletions tests/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8524,3 +8524,50 @@ fn test_fast_calls_callback_options_data() {
eval(scope, source).unwrap();
assert!(unsafe { DATA });
}

#[test]
fn test_detach_key() {
let _setup_guard = setup();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context);

// Object detach key
{
let detach_key = eval(scope, "({})").unwrap();
assert!(detach_key.is_object());
let buffer = v8::ArrayBuffer::new(scope, 1024);
buffer.set_detach_key(detach_key);
assert!(buffer.is_detachable());
assert_eq!(buffer.detach(v8::undefined(scope).into()), None);
assert!(!buffer.was_detached());
assert_eq!(buffer.detach(detach_key), Some(true));
assert!(buffer.was_detached());
}

// External detach key
{
let mut rust_detach_key = Box::new(42usize);
let v8_detach_key = v8::External::new(
scope,
&mut *rust_detach_key as *mut usize as *mut c_void,
);
let buffer = v8::ArrayBuffer::new(scope, 1024);
buffer.set_detach_key(v8_detach_key.into());
assert!(buffer.is_detachable());
assert_eq!(buffer.detach(v8::undefined(scope).into()), None);
assert!(!buffer.was_detached());
assert_eq!(buffer.detach(v8_detach_key.into()), Some(true));
assert!(buffer.was_detached());
}

// Undefined detach key
{
let buffer = v8::ArrayBuffer::new(scope, 1024);
buffer.set_detach_key(v8::undefined(scope).into());
assert!(buffer.is_detachable());
assert_eq!(buffer.detach(v8::undefined(scope).into()), Some(true));
assert!(buffer.was_detached());
}
}