mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-24 08:09:16 -05:00
add Object + ObjectTemplate internal field support (#477)
The rusty_v8 API deviates slightly from the V8 C++ API because the latter is definitely unsound when you pass in out-of-range indexes.
This commit is contained in:
parent
9bedd96d24
commit
6b90cbe499
4 changed files with 137 additions and 0 deletions
|
@ -733,6 +733,15 @@ const v8::Object* v8__ObjectTemplate__NewInstance(
|
|||
ptr_to_local(&self)->NewInstance(ptr_to_local(&context)));
|
||||
}
|
||||
|
||||
int v8__ObjectTemplate__InternalFieldCount(const v8::ObjectTemplate& self) {
|
||||
return ptr_to_local(&self)->InternalFieldCount();
|
||||
}
|
||||
|
||||
void v8__ObjectTemplate__SetInternalFieldCount(
|
||||
const v8::ObjectTemplate& self, int value) {
|
||||
ptr_to_local(&self)->SetInternalFieldCount(value);
|
||||
}
|
||||
|
||||
const v8::Object* v8__Object__New(v8::Isolate* isolate) {
|
||||
return local_to_ptr(v8::Object::New(isolate));
|
||||
}
|
||||
|
@ -866,6 +875,20 @@ MaybeBool v8__Object__DeleteIndex(const v8::Object& self,
|
|||
ptr_to_local(&self)->Delete(ptr_to_local(&context), index));
|
||||
}
|
||||
|
||||
int v8__Object__InternalFieldCount(const v8::Object& self) {
|
||||
return ptr_to_local(&self)->InternalFieldCount();
|
||||
}
|
||||
|
||||
const v8::Value* v8__Object__GetInternalField(const v8::Object& self,
|
||||
int index) {
|
||||
return local_to_ptr(ptr_to_local(&self)->GetInternalField(index));
|
||||
}
|
||||
|
||||
void v8__Object__SetInternalField(const v8::Object& self, int index,
|
||||
const v8::Value& value) {
|
||||
ptr_to_local(&self)->SetInternalField(index, ptr_to_local(&value));
|
||||
}
|
||||
|
||||
const v8::Array* v8__Array__New(v8::Isolate* isolate, int length) {
|
||||
return local_to_ptr(v8::Array::New(isolate, length));
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use crate::Name;
|
|||
use crate::Object;
|
||||
use crate::PropertyAttribute;
|
||||
use crate::Value;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
extern "C" {
|
||||
fn v8__Object__New(isolate: *mut Isolate) -> *const Object;
|
||||
|
@ -107,6 +108,16 @@ extern "C" {
|
|||
context: *const Context,
|
||||
index: u32,
|
||||
) -> MaybeBool;
|
||||
fn v8__Object__InternalFieldCount(this: *const Object) -> int;
|
||||
fn v8__Object__GetInternalField(
|
||||
this: *const Object,
|
||||
index: int,
|
||||
) -> *const Value;
|
||||
fn v8__Object__SetInternalField(
|
||||
this: *const Object,
|
||||
index: int,
|
||||
value: *const Value,
|
||||
);
|
||||
|
||||
fn v8__Array__New(isolate: *mut Isolate, length: int) -> *const Array;
|
||||
fn v8__Array__New_with_elements(
|
||||
|
@ -404,6 +415,48 @@ impl Object {
|
|||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Gets the number of internal fields for this Object.
|
||||
pub fn internal_field_count(&self) -> usize {
|
||||
let count = unsafe { v8__Object__InternalFieldCount(self) };
|
||||
usize::try_from(count).expect("bad internal field count") // Can't happen.
|
||||
}
|
||||
|
||||
/// Gets the value from an internal field.
|
||||
pub fn get_internal_field<'s>(
|
||||
&self,
|
||||
scope: &mut HandleScope<'s>,
|
||||
index: usize,
|
||||
) -> Option<Local<'s, Value>> {
|
||||
// Trying to access out-of-bounds internal fields makes V8 abort
|
||||
// in debug mode and access out-of-bounds memory in release mode.
|
||||
// The C++ API takes an i32 but doesn't check for indexes < 0, which
|
||||
// results in an out-of-bounds access in both debug and release mode.
|
||||
if index < self.internal_field_count() {
|
||||
if let Ok(index) = int::try_from(index) {
|
||||
return unsafe {
|
||||
scope.cast_local(|_| v8__Object__GetInternalField(self, index))
|
||||
};
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Sets the value in an internal field. Returns false when the index
|
||||
/// is out of bounds, true otherwise.
|
||||
pub fn set_internal_field(&self, index: usize, value: Local<Value>) -> bool {
|
||||
// Trying to access out-of-bounds internal fields makes V8 abort
|
||||
// in debug mode and access out-of-bounds memory in release mode.
|
||||
// The C++ API takes an i32 but doesn't check for indexes < 0, which
|
||||
// results in an out-of-bounds access in both debug and release mode.
|
||||
if index < self.internal_field_count() {
|
||||
if let Ok(index) = int::try_from(index) {
|
||||
unsafe { v8__Object__SetInternalField(self, index, &*value) };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl Array {
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::data::Name;
|
|||
use crate::data::ObjectTemplate;
|
||||
use crate::data::Template;
|
||||
use crate::isolate::Isolate;
|
||||
use crate::support::int;
|
||||
use crate::support::MapFnTo;
|
||||
use crate::Context;
|
||||
use crate::Function;
|
||||
|
@ -14,6 +15,7 @@ use crate::Object;
|
|||
use crate::PropertyAttribute;
|
||||
use crate::String;
|
||||
use crate::NONE;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
extern "C" {
|
||||
fn v8__Template__Set(
|
||||
|
@ -44,6 +46,12 @@ extern "C" {
|
|||
this: *const ObjectTemplate,
|
||||
context: *const Context,
|
||||
) -> *const Object;
|
||||
fn v8__ObjectTemplate__InternalFieldCount(this: *const ObjectTemplate)
|
||||
-> int;
|
||||
fn v8__ObjectTemplate__SetInternalFieldCount(
|
||||
this: *const ObjectTemplate,
|
||||
value: int,
|
||||
);
|
||||
}
|
||||
|
||||
impl Template {
|
||||
|
@ -132,4 +140,25 @@ impl ObjectTemplate {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the number of internal fields for objects generated from
|
||||
/// this template.
|
||||
pub fn internal_field_count(&self) -> usize {
|
||||
let count = unsafe { v8__ObjectTemplate__InternalFieldCount(self) };
|
||||
usize::try_from(count).expect("bad internal field count") // Can't happen.
|
||||
}
|
||||
|
||||
/// Sets the number of internal fields for objects generated from
|
||||
/// this template.
|
||||
pub fn set_internal_field_count(&self, value: usize) -> bool {
|
||||
// The C++ API takes an i32 but trying to set a value < 0
|
||||
// results in unpredictable behavior, hence we disallow it.
|
||||
match int::try_from(value) {
|
||||
Err(_) => false,
|
||||
Ok(value) => {
|
||||
unsafe { v8__ObjectTemplate__SetInternalFieldCount(self, value) };
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1132,6 +1132,25 @@ fn json() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_internal_field() {
|
||||
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);
|
||||
let object = v8::Object::new(scope);
|
||||
let value = v8::Integer::new(scope, 42).into();
|
||||
assert_eq!(0, object.internal_field_count());
|
||||
for index in &[0, 1, 1337] {
|
||||
assert!(object.get_internal_field(scope, *index).is_none());
|
||||
assert_eq!(false, object.set_internal_field(*index, value));
|
||||
assert!(object.get_internal_field(scope, *index).is_none());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn object_template() {
|
||||
let _setup_guard = setup();
|
||||
|
@ -1142,11 +1161,23 @@ fn object_template() {
|
|||
let function_templ = v8::FunctionTemplate::new(scope, fortytwo_callback);
|
||||
let name = v8::String::new(scope, "f").unwrap();
|
||||
let attr = v8::READ_ONLY + v8::DONT_ENUM + v8::DONT_DELETE;
|
||||
object_templ.set_internal_field_count(1);
|
||||
object_templ.set_with_attr(name.into(), function_templ.into(), attr);
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
|
||||
let object = object_templ.new_instance(scope).unwrap();
|
||||
assert!(!object.is_null_or_undefined());
|
||||
assert_eq!(1, object.internal_field_count());
|
||||
|
||||
let value = object.get_internal_field(scope, 0).unwrap();
|
||||
assert!(value.is_undefined());
|
||||
|
||||
let fortytwo = v8::Integer::new(scope, 42).into();
|
||||
assert_eq!(true, object.set_internal_field(0, fortytwo));
|
||||
let value = object.get_internal_field(scope, 0).unwrap();
|
||||
assert!(value.same_value(fortytwo));
|
||||
|
||||
let name = v8::String::new(scope, "g").unwrap();
|
||||
context.global(scope).define_own_property(
|
||||
scope,
|
||||
|
@ -1189,6 +1220,7 @@ fn object_template_from_function_template() {
|
|||
function_templ.set_class_name(expected_class_name);
|
||||
let object_templ =
|
||||
v8::ObjectTemplate::new_from_template(scope, function_templ);
|
||||
assert_eq!(0, object_templ.internal_field_count());
|
||||
let context = v8::Context::new(scope);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let object = object_templ.new_instance(scope).unwrap();
|
||||
|
|
Loading…
Reference in a new issue