diff --git a/allowed_bindings.rs b/allowed_bindings.rs index d9996ec..75d7207 100644 --- a/allowed_bindings.rs +++ b/allowed_bindings.rs @@ -217,6 +217,9 @@ bind! { _ZEND_TYPE_NULLABLE_BIT, ts_rsrc_id, _ZEND_TYPE_NAME_BIT, + ZEND_INTERNAL_FUNCTION, + ZEND_USER_FUNCTION, + ZEND_EVAL_CODE, zval_ptr_dtor, zend_refcounted_h, zend_is_true, @@ -264,5 +267,7 @@ bind! { sapi_header_struct, zend_is_auto_global, zend_llist_get_next_ex, - zend_llist_get_prev_ex + zend_llist_get_prev_ex, + zend_atomic_bool_store, + zend_interrupt_function } diff --git a/docsrs_bindings.rs b/docsrs_bindings.rs index 22817ac..01217bd 100644 --- a/docsrs_bindings.rs +++ b/docsrs_bindings.rs @@ -171,6 +171,9 @@ pub const ZEND_ACC_GENERATOR: u32 = 16777216; pub const ZEND_ACC_DONE_PASS_TWO: u32 = 33554432; pub const ZEND_ACC_HEAP_RT_CACHE: u32 = 67108864; pub const ZEND_ACC_STRICT_TYPES: u32 = 2147483648; +pub const ZEND_INTERNAL_FUNCTION: u32 = 1; +pub const ZEND_USER_FUNCTION: u32 = 2; +pub const ZEND_EVAL_CODE: u32 = 4; pub const ZEND_ISEMPTY: u32 = 1; pub const _ZEND_SEND_MODE_SHIFT: u32 = 25; pub const _ZEND_IS_VARIADIC_BIT: u32 = 134217728; @@ -901,6 +904,10 @@ pub struct _zend_class_entry__bindgen_ty_4__bindgen_ty_2 { pub builtin_functions: *const _zend_function_entry, pub module: *mut _zend_module_entry, } +extern "C" { + pub static mut zend_interrupt_function: + ::std::option::Option; +} extern "C" { pub static mut zend_standard_class_def: *mut zend_class_entry; } @@ -1284,6 +1291,9 @@ pub struct zend_atomic_bool_s { pub value: u8, } pub type zend_atomic_bool = zend_atomic_bool_s; +extern "C" { + pub fn zend_atomic_bool_store(obj: *mut zend_atomic_bool, desired: bool); +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _zend_stack { diff --git a/src/convert.rs b/src/convert.rs index 8782370..e1e2169 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -218,3 +218,13 @@ impl IntoZvalDyn for T { Self::TYPE } } + +impl IntoZvalDyn for Zval { + fn as_zval(&self, _persistent: bool) -> Result { + Ok(self.shallow_clone()) + } + + fn get_type(&self) -> DataType { + self.get_type() + } +} diff --git a/src/flags.rs b/src/flags.rs index 2dcdb6a..d2fbc37 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -20,8 +20,9 @@ use crate::ffi::{ ZEND_ACC_PROMOTED, ZEND_ACC_PROTECTED, ZEND_ACC_PUBLIC, ZEND_ACC_RESOLVED_INTERFACES, ZEND_ACC_RESOLVED_PARENT, ZEND_ACC_RETURN_REFERENCE, ZEND_ACC_STATIC, ZEND_ACC_STRICT_TYPES, ZEND_ACC_TOP_LEVEL, ZEND_ACC_TRAIT, ZEND_ACC_TRAIT_CLONE, ZEND_ACC_UNRESOLVED_VARIANCE, - ZEND_ACC_USES_THIS, ZEND_ACC_USE_GUARDS, ZEND_ACC_VARIADIC, ZEND_HAS_STATIC_IN_METHODS, - Z_TYPE_FLAGS_SHIFT, _IS_BOOL, + ZEND_ACC_USES_THIS, ZEND_ACC_USE_GUARDS, ZEND_ACC_VARIADIC, ZEND_EVAL_CODE, + ZEND_HAS_STATIC_IN_METHODS, ZEND_INTERNAL_FUNCTION, ZEND_USER_FUNCTION, Z_TYPE_FLAGS_SHIFT, + _IS_BOOL, }; use std::{convert::TryFrom, fmt::Display}; @@ -193,6 +194,24 @@ bitflags! { const UserDeprecated = E_USER_DEPRECATED; } } +#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)] +pub enum FunctionType { + Internal, + User, + Eval, +} + +impl From for FunctionType { + #[allow(clippy::bad_bit_mask)] + fn from(value: u8) -> Self { + match value as _ { + ZEND_INTERNAL_FUNCTION => Self::Internal, + ZEND_USER_FUNCTION => Self::User, + ZEND_EVAL_CODE => Self::Eval, + _ => panic!("Unknown function type: {}", value), + } + } +} /// Valid data types for PHP. #[repr(C, u8)] diff --git a/src/zend/class.rs b/src/zend/class.rs index dc06a32..6e7f796 100644 --- a/src/zend/class.rs +++ b/src/zend/class.rs @@ -79,6 +79,10 @@ impl ClassEntry { Self::try_find(name.as_str().ok()?) } } + + pub fn name(&self) -> Option<&str> { + unsafe { self.name.as_ref().and_then(|s| s.as_str().ok()) } + } } impl PartialEq for ClassEntry { diff --git a/src/zend/globals.rs b/src/zend/globals.rs index bf68e24..50afb52 100644 --- a/src/zend/globals.rs +++ b/src/zend/globals.rs @@ -7,6 +7,8 @@ use std::str; use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard}; use crate::boxed::ZBox; +#[cfg(php82)] +use crate::ffi::zend_atomic_bool_store; use crate::ffi::{ _zend_executor_globals, ext_php_rs_executor_globals, ext_php_rs_file_globals, ext_php_rs_process_globals, ext_php_rs_sapi_globals, php_core_globals, php_file_globals, @@ -80,6 +82,21 @@ impl ExecutorGlobals { // SAFETY: `as_mut` checks for null. Some(unsafe { ZBox::from_raw(exception_ptr.as_mut()?) }) } + + /// Request an interrupt of the PHP VM. This will call the registered + /// interrupt handler function. + /// set with [`crate::ffi::zend_interrupt_function`]. + pub fn request_interrupt(&mut self) { + cfg_if::cfg_if! { + if #[cfg(php82)] { + unsafe { + zend_atomic_bool_store(&mut self.vm_interrupt, true); + } + } else { + self.vm_interrupt = true; + } + } + } } /// Stores global variables used in the PHP executor.