diff --git a/src/binding.cc b/src/binding.cc index 24f75b52..6fc27049 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -65,6 +65,14 @@ static_assert(sizeof(v8::ReturnValue) == sizeof(size_t) * 1, static_assert(sizeof(v8::TryCatch) == sizeof(size_t) * 6, "TryCatch size mismatch"); +static_assert(sizeof(v8::Isolate::DisallowJavascriptExecutionScope) == + sizeof(size_t) * 2, + "DisallowJavascriptExecutionScope size mismatch"); + +static_assert(sizeof(v8::Isolate::AllowJavascriptExecutionScope) == + sizeof(size_t) * 2, + "AllowJavascriptExecutionScope size mismatch"); + static_assert(sizeof(v8::Location) == sizeof(int) * 2, "Location size mismatch"); @@ -2250,6 +2258,30 @@ void v8__TryCatch__SetCaptureMessage(v8::TryCatch* self, bool value) { self->SetCaptureMessage(value); } +void v8__DisallowJavascriptExecutionScope__CONSTRUCT( + uninit_t* buf, + v8::Isolate* isolate, + v8::Isolate::DisallowJavascriptExecutionScope::OnFailure on_failure) { + construct_in_place( + buf, isolate, on_failure); +} + +void v8__DisallowJavascriptExecutionScope__DESTRUCT( + v8::Isolate::DisallowJavascriptExecutionScope* self) { + self->~DisallowJavascriptExecutionScope(); +} + +void v8__AllowJavascriptExecutionScope__CONSTRUCT( + uninit_t* buf, + v8::Isolate* isolate) { + construct_in_place(buf, isolate); +} + +void v8__AllowJavascriptExecutionScope__DESTRUCT( + v8::Isolate::AllowJavascriptExecutionScope* self) { + self->~AllowJavascriptExecutionScope(); +} + #define V(NAME) \ const v8::NAME* v8__##NAME##__New(const v8::ArrayBuffer& buf_ptr, \ size_t byte_offset, size_t length) { \ diff --git a/src/lib.rs b/src/lib.rs index c38e541e..a205007a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -129,10 +129,13 @@ pub use property_descriptor::*; pub use property_filter::*; pub use property_handler_flags::*; pub use proxy::*; +pub use scope::AllowJavascriptExecutionScope; pub use scope::CallbackScope; pub use scope::ContextScope; +pub use scope::DisallowJavascriptExecutionScope; pub use scope::EscapableHandleScope; pub use scope::HandleScope; +pub use scope::OnFailure; pub use scope::TryCatch; pub use script::ScriptOrigin; pub use script_compiler::CachedData; diff --git a/src/scope.rs b/src/scope.rs index 8ccfadc6..00dfea56 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -76,6 +76,17 @@ //! - This scope type is only to be constructed inside embedder defined //! callbacks when these are called by V8. //! - When a scope is created inside, type is erased to `HandleScope<'s>`. +//! +//! - `DisallowJavascriptExecutionScope<'s, P>` +//! - 's = lifetime of the `DisallowJavascriptExecutionScope` scope. +//! - `P` is either a `HandleScope`, `ContextScope`, `EscapableHandleScope` +//! or a `TryCatch`. +//! - Derefs to `P`. +//! +//! - `AllowJavascriptExecutionScope<'s, P>` +//! - 's = lifetime of the `AllowJavascriptExecutionScope` scope. +//! - `P` is `DisallowJavascriptExecutionScope`. +//! - Derefs to `HandleScope<'s, ()>`. use std::alloc::alloc; use std::alloc::Layout; @@ -585,6 +596,50 @@ impl<'s> CallbackScope<'s> { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] +pub enum OnFailure { + CrashOnFailure, + ThrowOnFailure, + DumpOnFailure, +} + +#[derive(Debug)] +pub struct DisallowJavascriptExecutionScope<'s, P> { + _data: NonNull, + _phantom: PhantomData<&'s mut P>, +} + +impl<'s, P: param::NewDisallowJavascriptExecutionScope<'s>> + DisallowJavascriptExecutionScope<'s, P> +{ + #[allow(clippy::new_ret_no_self)] + pub fn new(param: &'s mut P, on_failure: OnFailure) -> P::NewScope { + param + .get_scope_data_mut() + .new_disallow_javascript_execution_scope_data(on_failure) + .as_scope() + } +} + +#[derive(Debug)] +pub struct AllowJavascriptExecutionScope<'s, P> { + _data: NonNull, + _phantom: PhantomData<&'s mut P>, +} + +impl<'s, P: param::NewAllowJavascriptExecutionScope<'s>> + AllowJavascriptExecutionScope<'s, P> +{ + #[allow(clippy::new_ret_no_self)] + pub fn new(param: &'s mut P) -> P::NewScope { + param + .get_scope_data_mut() + .new_allow_javascript_execution_scope_data() + .as_scope() + } +} + macro_rules! impl_as { // Implements `AsRef` and AsMut` on a scope type. (<$($params:tt),+> $src_type:ty as Isolate) => { @@ -622,6 +677,8 @@ impl_as!(<'s, 'p, P> ContextScope<'s, P> as Isolate); impl_as!(<'s, C> HandleScope<'s, C> as Isolate); impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as Isolate); impl_as!(<'s, P> TryCatch<'s, P> as Isolate); +impl_as!(<'s, P> DisallowJavascriptExecutionScope<'s, P> as Isolate); +impl_as!(<'s, P> AllowJavascriptExecutionScope<'s, P> as Isolate); impl_as!(<'s, C> CallbackScope<'s, C> as Isolate); impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p, ()>); @@ -630,6 +687,10 @@ impl_as!(<'s, C> HandleScope<'s, C> as HandleScope<'s, ()>); impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as HandleScope<'s, ()>); impl_as!(<'s, 'p, C> TryCatch<'s, HandleScope<'p, C>> as HandleScope<'p, ()>); impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as HandleScope<'p, ()>); +impl_as!(<'s, 'p, C> DisallowJavascriptExecutionScope<'s, HandleScope<'p, C>> as HandleScope<'p, ()>); +impl_as!(<'s, 'p, 'e, C> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as HandleScope<'p, ()>); +impl_as!(<'s, 'p, C> AllowJavascriptExecutionScope<'s, HandleScope<'p, C>> as HandleScope<'p, ()>); +impl_as!(<'s, 'p, 'e, C> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as HandleScope<'p, ()>); impl_as!(<'s, C> CallbackScope<'s, C> as HandleScope<'s, ()>); impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p>); @@ -638,15 +699,23 @@ impl_as!(<'s> HandleScope<'s> as HandleScope<'s>); impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>); impl_as!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as HandleScope<'p>); impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>); +impl_as!(<'s, 'p> DisallowJavascriptExecutionScope<'s, HandleScope<'p>> as HandleScope<'p>); +impl_as!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>); +impl_as!(<'s, 'p> AllowJavascriptExecutionScope<'s, HandleScope<'p>> as HandleScope<'p>); +impl_as!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>); impl_as!(<'s> CallbackScope<'s> as HandleScope<'s>); impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e, ()>); impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as EscapableHandleScope<'s, 'e, ()>); impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as EscapableHandleScope<'p, 'e, ()>); +impl_as!(<'s, 'p, 'e, C> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as EscapableHandleScope<'p, 'e, ()>); +impl_as!(<'s, 'p, 'e, C> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as EscapableHandleScope<'p, 'e, ()>); impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as EscapableHandleScope<'s, 'e>); impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); +impl_as!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); +impl_as!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); impl_as!(<'s, 'p, C> TryCatch<'s, HandleScope<'p, C>> as TryCatch<'s, HandleScope<'p, ()>>); impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as TryCatch<'s, HandleScope<'p, ()>>); @@ -656,6 +725,25 @@ impl_as!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as TryCatch<'s, HandleScope<'p>> impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as TryCatch<'s, HandleScope<'p>>); impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as TryCatch<'s, EscapableHandleScope<'p, 'e>>); +impl_as!(<'s, 'p, C> DisallowJavascriptExecutionScope<'s, HandleScope<'p, C>> as DisallowJavascriptExecutionScope<'s, HandleScope<'p, ()>>); +impl_as!(<'s, 'p, 'e, C> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as DisallowJavascriptExecutionScope<'s, HandleScope<'p, ()>>); +impl_as!(<'s, 'p, 'e, C> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, ()>>); + +impl_as!(<'s, 'p> DisallowJavascriptExecutionScope<'s, HandleScope<'p>> as DisallowJavascriptExecutionScope<'s, HandleScope<'p>>); +impl_as!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as DisallowJavascriptExecutionScope<'s, HandleScope<'p>>); +impl_as!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>>); + +impl_as!(<'s, 'p, C> AllowJavascriptExecutionScope<'s, HandleScope<'p, C>> as AllowJavascriptExecutionScope<'s, HandleScope<'p, ()>>); +impl_as!(<'s, 'p, 'e, C> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as AllowJavascriptExecutionScope<'s, HandleScope<'p, ()>>); +impl_as!(<'s, 'p, 'e, C> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, ()>>); + +impl_as!(<'s, 'p> AllowJavascriptExecutionScope<'s, HandleScope<'p>> as AllowJavascriptExecutionScope<'s, HandleScope<'p>>); +impl_as!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as AllowJavascriptExecutionScope<'s, HandleScope<'p>>); +impl_as!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>>); + +impl_as!(<'s, 'p, P> DisallowJavascriptExecutionScope<'s, TryCatch<'p, P>> as TryCatch<'p, P>); +impl_as!(<'s, 'p, P> AllowJavascriptExecutionScope<'s, TryCatch<'p, P>> as TryCatch<'p, P>); + macro_rules! impl_deref { (<$($params:tt),+> $src_type:ty as $tgt_type:ty) => { impl<$($params),*> Deref for $src_type { @@ -687,6 +775,18 @@ impl_deref!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as HandleScope<'p>); impl_deref!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e, ()>> as EscapableHandleScope<'p, 'e, ()>); impl_deref!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); +impl_deref!(<'s, 'p> DisallowJavascriptExecutionScope<'s, HandleScope<'p, ()>> as HandleScope<'p, ()>); +impl_deref!(<'s, 'p> DisallowJavascriptExecutionScope<'s, HandleScope<'p>> as HandleScope<'p>); +impl_deref!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, ()>> as EscapableHandleScope<'p, 'e, ()>); +impl_deref!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); +impl_deref!(<'s, 'p, P> DisallowJavascriptExecutionScope<'s, TryCatch<'p, P>> as TryCatch<'p, P>); + +impl_deref!(<'s, 'p> AllowJavascriptExecutionScope<'s, HandleScope<'p, ()>> as HandleScope<'p, ()>); +impl_deref!(<'s, 'p> AllowJavascriptExecutionScope<'s, HandleScope<'p>> as HandleScope<'p>); +impl_deref!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, ()>> as EscapableHandleScope<'p, 'e, ()>); +impl_deref!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); +impl_deref!(<'s, 'p, P> AllowJavascriptExecutionScope<'s, TryCatch<'p, P>> as TryCatch<'p, P>); + impl_deref!(<'s> CallbackScope<'s, ()> as HandleScope<'s, ()>); impl_deref!(<'s> CallbackScope<'s> as HandleScope<'s>); @@ -707,6 +807,8 @@ impl_scope_drop!(<'s, 'p, P> ContextScope<'s, P>); impl_scope_drop!(<'s, C> HandleScope<'s, C> ); impl_scope_drop!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> ); impl_scope_drop!(<'s, P> TryCatch<'s, P> ); +impl_scope_drop!(<'s, P> DisallowJavascriptExecutionScope<'s, P>); +impl_scope_drop!(<'s, P> AllowJavascriptExecutionScope<'s, P>); impl_scope_drop!(<'s, C> CallbackScope<'s, C> ); pub unsafe trait Scope: Sized {} @@ -768,6 +870,18 @@ mod param { type NewScope =

>::NewScope; } + impl<'s, 'p: 's, P: NewContextScope<'s>> NewContextScope<'s> + for DisallowJavascriptExecutionScope<'p, P> + { + type NewScope =

>::NewScope; + } + + impl<'s, 'p: 's, P: NewContextScope<'s>> NewContextScope<'s> + for AllowJavascriptExecutionScope<'p, P> + { + type NewScope =

>::NewScope; + } + impl<'s, 'p: 's, C> NewContextScope<'s> for CallbackScope<'p, C> { type NewScope = ContextScope<'s, HandleScope<'p>>; } @@ -804,6 +918,18 @@ mod param { type NewScope =

>::NewScope; } + impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s> + for DisallowJavascriptExecutionScope<'p, P> + { + type NewScope =

>::NewScope; + } + + impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s> + for AllowJavascriptExecutionScope<'p, P> + { + type NewScope =

>::NewScope; + } + impl<'s, 'p: 's, C> NewHandleScope<'s> for CallbackScope<'p, C> { type NewScope = HandleScope<'s, C>; } @@ -850,6 +976,19 @@ mod param { type NewScope =

>::NewScope; } + impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>> + NewEscapableHandleScope<'s, 'e> + for DisallowJavascriptExecutionScope<'p, P> + { + type NewScope =

>::NewScope; + } + + impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>> + NewEscapableHandleScope<'s, 'e> for AllowJavascriptExecutionScope<'p, P> + { + type NewScope =

>::NewScope; + } + impl<'s, 'p: 's, C> NewEscapableHandleScope<'s, 'p> for CallbackScope<'p, C> { type NewScope = EscapableHandleScope<'s, 'p, C>; } @@ -876,10 +1015,101 @@ mod param { type NewScope = TryCatch<'s, P>; } + impl<'s, 'p: 's, P> NewTryCatch<'s> + for DisallowJavascriptExecutionScope<'p, P> + { + type NewScope = TryCatch<'s, P>; + } + + impl<'s, 'p: 's, P> NewTryCatch<'s> for AllowJavascriptExecutionScope<'p, P> { + type NewScope = TryCatch<'s, P>; + } + impl<'s, 'p: 's, C> NewTryCatch<'s> for CallbackScope<'p, C> { type NewScope = TryCatch<'s, HandleScope<'p, C>>; } + pub trait NewDisallowJavascriptExecutionScope<'s>: + getter::GetScopeData + { + type NewScope: Scope; + } + + impl<'s, 'p: 's, P: NewDisallowJavascriptExecutionScope<'s>> + NewDisallowJavascriptExecutionScope<'s> for ContextScope<'p, P> + { + type NewScope =

>::NewScope; + } + + impl<'s, 'p: 's, C> NewDisallowJavascriptExecutionScope<'s> + for HandleScope<'p, C> + { + type NewScope = DisallowJavascriptExecutionScope<'s, HandleScope<'p, C>>; + } + + impl<'s, 'p: 's, 'e: 'p, C> NewDisallowJavascriptExecutionScope<'s> + for EscapableHandleScope<'p, 'e, C> + { + type NewScope = + DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>>; + } + + impl<'s, 'p: 's, P> NewDisallowJavascriptExecutionScope<'s> + for TryCatch<'p, P> + { + type NewScope = DisallowJavascriptExecutionScope<'s, TryCatch<'p, P>>; + } + + impl<'s, 'p: 's, P> NewDisallowJavascriptExecutionScope<'s> + for DisallowJavascriptExecutionScope<'p, P> + { + type NewScope = DisallowJavascriptExecutionScope<'s, P>; + } + + impl<'s, 'p: 's, P> NewDisallowJavascriptExecutionScope<'s> + for AllowJavascriptExecutionScope<'p, P> + { + type NewScope = DisallowJavascriptExecutionScope<'s, P>; + } + + pub trait NewAllowJavascriptExecutionScope<'s>: getter::GetScopeData { + type NewScope: Scope; + } + + impl<'s, 'p: 's, P: NewAllowJavascriptExecutionScope<'s>> + NewAllowJavascriptExecutionScope<'s> for ContextScope<'p, P> + { + type NewScope =

>::NewScope; + } + + impl<'s, 'p: 's, C> NewAllowJavascriptExecutionScope<'s> + for HandleScope<'p, C> + { + type NewScope = HandleScope<'p, C>; + } + + impl<'s, 'p: 's, 'e: 'p, C> NewAllowJavascriptExecutionScope<'s> + for EscapableHandleScope<'p, 'e, C> + { + type NewScope = EscapableHandleScope<'p, 'e, C>; + } + + impl<'s, 'p: 's, P> NewAllowJavascriptExecutionScope<'s> for TryCatch<'p, P> { + type NewScope = TryCatch<'s, P>; + } + + impl<'s, 'p: 's, P: Scope> NewAllowJavascriptExecutionScope<'s> + for DisallowJavascriptExecutionScope<'p, P> + { + type NewScope = P; + } + + impl<'s, 'p: 's, P> NewAllowJavascriptExecutionScope<'s> + for AllowJavascriptExecutionScope<'p, P> + { + type NewScope = AllowJavascriptExecutionScope<'s, P>; + } + pub trait NewCallbackScope<'s>: Sized + getter::GetIsolate<'s> { type NewScope: Scope; @@ -1226,6 +1456,49 @@ pub(crate) mod data { }) } + #[inline(always)] + pub(super) fn new_disallow_javascript_execution_scope_data( + &mut self, + on_failure: OnFailure, + ) -> &mut Self { + self.new_scope_data_with(|data| { + let isolate = data.isolate; + data.scope_type_specific_data.init_with(|| { + ScopeTypeSpecificData::DisallowJavascriptExecutionScope { + raw_scope: unsafe { + raw::DisallowJavascriptExecutionScope::uninit() + }, + } + }); + match &mut data.scope_type_specific_data { + ScopeTypeSpecificData::DisallowJavascriptExecutionScope { + raw_scope, + } => unsafe { raw_scope.init(isolate, on_failure) }, + _ => unreachable!(), + } + }) + } + + #[inline(always)] + pub(super) fn new_allow_javascript_execution_scope_data( + &mut self, + ) -> &mut Self { + self.new_scope_data_with(|data| { + let isolate = data.isolate; + data.scope_type_specific_data.init_with(|| { + ScopeTypeSpecificData::AllowJavascriptExecutionScope { + raw_scope: unsafe { raw::AllowJavascriptExecutionScope::uninit() }, + } + }); + match &mut data.scope_type_specific_data { + ScopeTypeSpecificData::AllowJavascriptExecutionScope { + raw_scope, + } => unsafe { raw_scope.init(isolate) }, + _ => unreachable!(), + } + }) + } + #[inline(always)] pub(super) fn new_callback_scope_data<'s>( &'s mut self, @@ -1553,6 +1826,12 @@ pub(crate) mod data { TryCatch { raw_try_catch: raw::TryCatch, }, + DisallowJavascriptExecutionScope { + raw_scope: raw::DisallowJavascriptExecutionScope, + }, + AllowJavascriptExecutionScope { + raw_scope: raw::AllowJavascriptExecutionScope, + }, } impl Default for ScopeTypeSpecificData { @@ -1714,6 +1993,77 @@ mod raw { } } + #[repr(C)] + #[derive(Debug)] + pub(super) struct DisallowJavascriptExecutionScope([MaybeUninit; 2]); + + impl DisallowJavascriptExecutionScope { + /// Creates an uninitialized `DisallowJavascriptExecutionScope`. + /// + /// This function is marked unsafe because the caller must ensure that the + /// returned value isn't dropped before `init()` has been called. + pub unsafe fn uninit() -> Self { + Self(MaybeUninit::uninit().assume_init()) + } + + /// This function is marked unsafe because `init()` must be called exactly + /// once, no more and no less, after creating a + /// `DisallowJavascriptExecutionScope` value with + /// `DisallowJavascriptExecutionScope::uninit()`. + pub unsafe fn init( + &mut self, + isolate: NonNull, + on_failure: OnFailure, + ) { + let buf = NonNull::from(self).cast(); + v8__DisallowJavascriptExecutionScope__CONSTRUCT( + buf.as_ptr(), + isolate.as_ptr(), + on_failure, + ); + } + } + + impl Drop for DisallowJavascriptExecutionScope { + #[inline(always)] + fn drop(&mut self) { + unsafe { v8__DisallowJavascriptExecutionScope__DESTRUCT(self) }; + } + } + + #[repr(C)] + #[derive(Debug)] + pub(super) struct AllowJavascriptExecutionScope([MaybeUninit; 2]); + + impl AllowJavascriptExecutionScope { + /// Creates an uninitialized `AllowJavascriptExecutionScope`. + /// + /// This function is marked unsafe because the caller must ensure that the + /// returned value isn't dropped before `init()` has been called. + pub unsafe fn uninit() -> Self { + Self(MaybeUninit::uninit().assume_init()) + } + + /// This function is marked unsafe because `init()` must be called exactly + /// once, no more and no less, after creating an + /// `AllowJavascriptExecutionScope` value with + /// `AllowJavascriptExecutionScope::uninit()`. + pub unsafe fn init(&mut self, isolate: NonNull) { + let buf = NonNull::from(self).cast(); + v8__AllowJavascriptExecutionScope__CONSTRUCT( + buf.as_ptr(), + isolate.as_ptr(), + ); + } + } + + impl Drop for AllowJavascriptExecutionScope { + #[inline(always)] + fn drop(&mut self) { + unsafe { v8__AllowJavascriptExecutionScope__DESTRUCT(self) }; + } + } + extern "C" { pub(super) fn v8__Isolate__GetCurrentContext( isolate: *mut Isolate, @@ -1796,6 +2146,23 @@ mod raw { ) -> *const Message; pub(super) fn v8__TryCatch__ReThrow(this: *mut TryCatch) -> *const Value; + pub(super) fn v8__DisallowJavascriptExecutionScope__CONSTRUCT( + buf: *mut MaybeUninit, + isolate: *mut Isolate, + on_failure: OnFailure, + ); + pub(super) fn v8__DisallowJavascriptExecutionScope__DESTRUCT( + this: *mut DisallowJavascriptExecutionScope, + ); + + pub(super) fn v8__AllowJavascriptExecutionScope__CONSTRUCT( + buf: *mut MaybeUninit, + isolate: *mut Isolate, + ); + pub(super) fn v8__AllowJavascriptExecutionScope__DESTRUCT( + this: *mut AllowJavascriptExecutionScope, + ); + pub(super) fn v8__Message__GetIsolate(this: *const Message) -> *mut Isolate; pub(super) fn v8__Object__GetIsolate(this: *const Object) -> *mut Isolate; @@ -1865,6 +2232,28 @@ mod tests { let d = d.deref_mut(); AssertTypeOf(d).is::(); } + { + let l3_djses = &mut DisallowJavascriptExecutionScope::new( + l2_cxs, + OnFailure::CrashOnFailure, + ); + AssertTypeOf(l3_djses) + .is::>(); + let d = l3_djses.deref_mut(); + AssertTypeOf(d).is::(); + let d = d.deref_mut(); + AssertTypeOf(d).is::>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::(); + { + let l4_ajses = &mut AllowJavascriptExecutionScope::new(l3_djses); + AssertTypeOf(l4_ajses).is::(); + let d = l4_ajses.deref_mut(); + AssertTypeOf(d).is::>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::(); + } + } { let l3_ehs = &mut EscapableHandleScope::new(l2_cxs); AssertTypeOf(l3_ehs).is::(); @@ -1892,6 +2281,32 @@ mod tests { let d = d.deref_mut(); AssertTypeOf(d).is::(); } + { + let l4_djses = &mut DisallowJavascriptExecutionScope::new( + l3_ehs, + OnFailure::CrashOnFailure, + ); + AssertTypeOf(l4_djses) + .is::>(); + let d = l4_djses.deref_mut(); + AssertTypeOf(d).is::(); + let d = d.deref_mut(); + AssertTypeOf(d).is::(); + let d = d.deref_mut(); + AssertTypeOf(d).is::>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::(); + { + let l5_ajses = &mut AllowJavascriptExecutionScope::new(l4_djses); + AssertTypeOf(l5_ajses).is::(); + let d = l5_ajses.deref_mut(); + AssertTypeOf(d).is::(); + let d = d.deref_mut(); + AssertTypeOf(d).is::>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::(); + } + } } } { @@ -1901,6 +2316,28 @@ mod tests { AssertTypeOf(d).is::>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); + { + let l3_djses = &mut DisallowJavascriptExecutionScope::new( + l2_tc, + OnFailure::CrashOnFailure, + ); + AssertTypeOf(l3_djses) + .is::>>>(); + let d = l3_djses.deref_mut(); + AssertTypeOf(d).is::>>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::(); + { + let l4_ajses = &mut AllowJavascriptExecutionScope::new(l3_djses); + AssertTypeOf(l4_ajses).is::>>(); + let d = l4_ajses.deref_mut(); + AssertTypeOf(d).is::>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::(); + } + } } { let l2_ehs = &mut EscapableHandleScope::new(l1_hs); diff --git a/tests/compile_fail/handle_scope_escape_to_nowhere.stderr b/tests/compile_fail/handle_scope_escape_to_nowhere.stderr index 7fe08661..d0021e1b 100644 --- a/tests/compile_fail/handle_scope_escape_to_nowhere.stderr +++ b/tests/compile_fail/handle_scope_escape_to_nowhere.stderr @@ -7,8 +7,10 @@ error[E0277]: the trait bound `OwnedIsolate: v8::scope::param::NewEscapableHandl | required by a bound introduced by this call | = help: the following other types implement trait `v8::scope::param::NewEscapableHandleScope<'s, 'e>`: + as v8::scope::param::NewEscapableHandleScope<'s, 'e>> as v8::scope::param::NewEscapableHandleScope<'s, 'p>> as v8::scope::param::NewEscapableHandleScope<'s, 'e>> + as v8::scope::param::NewEscapableHandleScope<'s, 'e>> as v8::scope::param::NewEscapableHandleScope<'s, 'p>> as v8::scope::param::NewEscapableHandleScope<'s, 'p>> as v8::scope::param::NewEscapableHandleScope<'s, 'e>> @@ -25,8 +27,10 @@ error[E0277]: the trait bound `OwnedIsolate: v8::scope::param::NewEscapableHandl | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `v8::scope::param::NewEscapableHandleScope<'_, '_>` is not implemented for `OwnedIsolate` | = help: the following other types implement trait `v8::scope::param::NewEscapableHandleScope<'s, 'e>`: + as v8::scope::param::NewEscapableHandleScope<'s, 'e>> as v8::scope::param::NewEscapableHandleScope<'s, 'p>> as v8::scope::param::NewEscapableHandleScope<'s, 'e>> + as v8::scope::param::NewEscapableHandleScope<'s, 'e>> as v8::scope::param::NewEscapableHandleScope<'s, 'p>> as v8::scope::param::NewEscapableHandleScope<'s, 'p>> as v8::scope::param::NewEscapableHandleScope<'s, 'e>> @@ -38,8 +42,10 @@ error[E0277]: the trait bound `OwnedIsolate: v8::scope::param::NewEscapableHandl | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `v8::scope::param::NewEscapableHandleScope<'_, '_>` is not implemented for `OwnedIsolate` | = help: the following other types implement trait `v8::scope::param::NewEscapableHandleScope<'s, 'e>`: + as v8::scope::param::NewEscapableHandleScope<'s, 'e>> as v8::scope::param::NewEscapableHandleScope<'s, 'p>> as v8::scope::param::NewEscapableHandleScope<'s, 'e>> + as v8::scope::param::NewEscapableHandleScope<'s, 'e>> as v8::scope::param::NewEscapableHandleScope<'s, 'p>> as v8::scope::param::NewEscapableHandleScope<'s, 'p>> as v8::scope::param::NewEscapableHandleScope<'s, 'e>> diff --git a/tests/test_api.rs b/tests/test_api.rs index 385a8c93..fb79fb0a 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -10647,3 +10647,124 @@ fn exception_thrown_but_continues_execution() { let _result = script.run(scope); assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 2); } + +#[test] +fn disallow_javascript_execution_scope() { + let _setup_guard = setup::parallel_test(); + + let mut isolate = v8::Isolate::new(Default::default()); + let mut scope = v8::HandleScope::new(&mut isolate); + let context = v8::Context::new(&mut scope); + let mut scope = v8::ContextScope::new(&mut scope, context); + + // We can run JS before the scope begins. + assert_eq!( + eval(&mut scope, "42").unwrap().uint32_value(&mut scope), + Some(42) + ); + + { + let try_catch = &mut v8::TryCatch::new(&mut scope); + { + let scope = &mut v8::DisallowJavascriptExecutionScope::new( + try_catch, + v8::OnFailure::ThrowOnFailure, + ); + assert!(eval(scope, "42").is_none()); + } + assert!(try_catch.has_caught()); + try_catch.reset(); + } + + // And we can run JS after the scope ends. + assert_eq!( + eval(&mut scope, "42").unwrap().uint32_value(&mut scope), + Some(42) + ); +} + +// TODO: Test DisallowJavascriptExecutionScope with OnFailure::CrashOnFailure +// and OnFailure::DumpOnFailure. #[should_panic] obviously doesn't work on +// those. + +#[test] +fn allow_javascript_execution_scope() { + let _setup_guard = setup::parallel_test(); + + let mut isolate = v8::Isolate::new(Default::default()); + let mut scope = v8::HandleScope::new(&mut isolate); + let context = v8::Context::new(&mut scope); + let mut scope = v8::ContextScope::new(&mut scope, context); + + let disallow_scope = &mut v8::DisallowJavascriptExecutionScope::new( + &mut scope, + v8::OnFailure::CrashOnFailure, + ); + let allow_scope = &mut v8::AllowJavascriptExecutionScope::new(disallow_scope); + assert_eq!( + eval(allow_scope, "42").unwrap().uint32_value(allow_scope), + Some(42) + ); +} + +#[test] +fn allow_scope_in_read_host_object() { + // The scope that is passed to ValueDeserializerImpl::read_host_object is + // internally a DisallowJavascriptExecutionScope, so an allow scope must be + // created in order to run JS code in that callback. + struct Serializer; + impl v8::ValueSerializerImpl for Serializer { + fn write_host_object<'s>( + &mut self, + _scope: &mut v8::HandleScope<'s>, + _object: v8::Local<'s, v8::Object>, + _value_serializer: &mut dyn v8::ValueSerializerHelper, + ) -> Option { + // Doesn't look at the object or writes anything. + Some(true) + } + + fn throw_data_clone_error<'s>( + &mut self, + _scope: &mut v8::HandleScope<'s>, + _message: v8::Local<'s, v8::String>, + ) { + todo!() + } + } + + struct Deserializer; + impl v8::ValueDeserializerImpl for Deserializer { + fn read_host_object<'s>( + &mut self, + scope: &mut v8::HandleScope<'s>, + _value_deserializer: &mut dyn v8::ValueDeserializerHelper, + ) -> Option> { + let scope2 = &mut v8::AllowJavascriptExecutionScope::new(scope); + let value = eval(scope2, "{}").unwrap(); + let object = v8::Local::::try_from(value).unwrap(); + Some(object) + } + } + + let _setup_guard = setup::parallel_test(); + + let mut isolate = v8::Isolate::new(Default::default()); + let mut scope = v8::HandleScope::new(&mut isolate); + let context = v8::Context::new(&mut scope); + let mut scope = v8::ContextScope::new(&mut scope, context); + + let serialized = { + let mut serializer = + v8::ValueSerializer::new(&mut scope, Box::new(Serializer)); + serializer + .write_value(context, v8::Object::new(&mut scope).into()) + .unwrap(); + serializer.release() + }; + + let mut deserializer = + v8::ValueDeserializer::new(&mut scope, Box::new(Deserializer), &serialized); + let value = deserializer.read_value(context).unwrap(); + assert!(value.is_object()); +}