diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fe68b07ed..557d80cd5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - php: ["8.0", "8.1", "8.2"] + php: ["8.0", "8.1", "8.2", "8.3"] rust: [stable, nightly] clang: ["14"] phpts: [ts, nts] diff --git a/allowed_bindings.rs b/allowed_bindings.rs index ca2195bde..53e5a5e2e 100644 --- a/allowed_bindings.rs +++ b/allowed_bindings.rs @@ -26,6 +26,7 @@ bind! { _efree, _emalloc, _zend_executor_globals, + _sapi_globals_struct, _zend_expected_type, _zend_expected_type_Z_EXPECTED_ARRAY, _zend_expected_type_Z_EXPECTED_BOOL, @@ -241,6 +242,7 @@ bind! { zend_class_serialize_deny, zend_class_unserialize_deny, zend_executor_globals, + sapi_globals_struct, zend_objects_store_del, zend_hash_move_forward_ex, zend_hash_get_current_key_type_ex, @@ -251,10 +253,12 @@ bind! { gc_possible_root, ZEND_ACC_NOT_SERIALIZABLE, executor_globals, + sapi_globals, php_printf, __zend_malloc, tsrm_get_ls_cache, executor_globals_offset, + sapi_globals_offset, zend_atomic_bool_store, zend_interrupt_function, zend_eval_string, diff --git a/build.rs b/build.rs index 78c9cf322..5afef52e2 100644 --- a/build.rs +++ b/build.rs @@ -16,7 +16,7 @@ use bindgen::RustTarget; use impl_::Provider; const MIN_PHP_API_VER: u32 = 20200930; -const MAX_PHP_API_VER: u32 = 20220829; +const MAX_PHP_API_VER: u32 = 20230831; pub trait PHPProvider<'a>: Sized { /// Create a new PHP provider. @@ -228,6 +228,8 @@ fn check_php_version(info: &PHPInfo) -> Result<()> { const PHP_82_API_VER: u32 = 20220829; + const PHP_83_API_VER: u32 = 20230831; + println!("cargo:rustc-cfg=php80"); if (PHP_81_API_VER..PHP_82_API_VER).contains(&version) { @@ -238,6 +240,10 @@ fn check_php_version(info: &PHPInfo) -> Result<()> { println!("cargo:rustc-cfg=php82"); } + if version >= PHP_83_API_VER { + println!("cargo:rustc-cfg=php83"); + } + Ok(()) } diff --git a/docsrs_bindings.rs b/docsrs_bindings.rs index f7e54f1e2..dd3978a47 100644 --- a/docsrs_bindings.rs +++ b/docsrs_bindings.rs @@ -1,5 +1,85 @@ /* automatically generated by rust-bindgen 0.68.1 */ +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit { + storage: Storage, +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + pub fn get_bit(&self, index: usize) -> bool { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = self.storage.as_ref()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { + *byte |= mask; + } else { + *byte &= !mask; + } + } + #[inline] + pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + let mut val = 0; + for i in 0..(bit_width as usize) { + if self.get_bit(i + bit_offset) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] + pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + self.set_bit(index + bit_offset, val_bit_is_set); + } + } +} pub const ZEND_DEBUG: u32 = 1; pub const _ZEND_TYPE_NAME_BIT: u32 = 16777216; pub const _ZEND_TYPE_NULLABLE_BIT: u32 = 2; @@ -97,7 +177,7 @@ 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; -pub const ZEND_MODULE_API_NO: u32 = 20220829; +pub const ZEND_MODULE_API_NO: u32 = 20230831; pub const USING_ZTS: u32 = 0; pub const MAY_BE_BOOL: u32 = 12; pub const MAY_BE_ANY: u32 = 1022; @@ -109,68 +189,82 @@ pub const CONST_CS: u32 = 0; pub const CONST_PERSISTENT: u32 = 1; pub const CONST_NO_FILE_CACHE: u32 = 2; pub const CONST_DEPRECATED: u32 = 4; -pub type __int64_t = ::std::os::raw::c_longlong; -pub type __darwin_off_t = __int64_t; -pub type fpos_t = __darwin_off_t; +pub type __dev_t = ::std::os::raw::c_ulong; +pub type __uid_t = ::std::os::raw::c_uint; +pub type __gid_t = ::std::os::raw::c_uint; +pub type __ino_t = ::std::os::raw::c_ulong; +pub type __mode_t = ::std::os::raw::c_uint; +pub type __nlink_t = ::std::os::raw::c_ulong; +pub type __off_t = ::std::os::raw::c_long; +pub type __off64_t = ::std::os::raw::c_long; +pub type __time_t = ::std::os::raw::c_long; +pub type __blksize_t = ::std::os::raw::c_long; +pub type __blkcnt_t = ::std::os::raw::c_long; +pub type __syscall_slong_t = ::std::os::raw::c_long; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __sigset_t { + pub __val: [::std::os::raw::c_ulong; 16usize], +} #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct __sbuf { - pub _base: *mut ::std::os::raw::c_uchar, - pub _size: ::std::os::raw::c_int, +pub struct timespec { + pub tv_sec: __time_t, + pub tv_nsec: __syscall_slong_t, } +pub type FILE = _IO_FILE; #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct __sFILEX { +pub struct _IO_marker { _unused: [u8; 0], } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct __sFILE { - pub _p: *mut ::std::os::raw::c_uchar, - pub _r: ::std::os::raw::c_int, - pub _w: ::std::os::raw::c_int, - pub _flags: ::std::os::raw::c_short, - pub _file: ::std::os::raw::c_short, - pub _bf: __sbuf, - pub _lbfsize: ::std::os::raw::c_int, - pub _cookie: *mut ::std::os::raw::c_void, - pub _close: ::std::option::Option< - unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int, - >, - pub _read: ::std::option::Option< - unsafe extern "C" fn( - arg1: *mut ::std::os::raw::c_void, - arg2: *mut ::std::os::raw::c_char, - arg3: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int, - >, - pub _seek: ::std::option::Option< - unsafe extern "C" fn( - arg1: *mut ::std::os::raw::c_void, - arg2: fpos_t, - arg3: ::std::os::raw::c_int, - ) -> fpos_t, - >, - pub _write: ::std::option::Option< - unsafe extern "C" fn( - arg1: *mut ::std::os::raw::c_void, - arg2: *const ::std::os::raw::c_char, - arg3: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int, - >, - pub _ub: __sbuf, - pub _extra: *mut __sFILEX, - pub _ur: ::std::os::raw::c_int, - pub _ubuf: [::std::os::raw::c_uchar; 3usize], - pub _nbuf: [::std::os::raw::c_uchar; 1usize], - pub _lb: __sbuf, - pub _blksize: ::std::os::raw::c_int, - pub _offset: fpos_t, -} -pub type FILE = __sFILE; +pub struct _IO_codecvt { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _IO_wide_data { + _unused: [u8; 0], +} +pub type _IO_lock_t = ::std::os::raw::c_void; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _IO_FILE { + pub _flags: ::std::os::raw::c_int, + pub _IO_read_ptr: *mut ::std::os::raw::c_char, + pub _IO_read_end: *mut ::std::os::raw::c_char, + pub _IO_read_base: *mut ::std::os::raw::c_char, + pub _IO_write_base: *mut ::std::os::raw::c_char, + pub _IO_write_ptr: *mut ::std::os::raw::c_char, + pub _IO_write_end: *mut ::std::os::raw::c_char, + pub _IO_buf_base: *mut ::std::os::raw::c_char, + pub _IO_buf_end: *mut ::std::os::raw::c_char, + pub _IO_save_base: *mut ::std::os::raw::c_char, + pub _IO_backup_base: *mut ::std::os::raw::c_char, + pub _IO_save_end: *mut ::std::os::raw::c_char, + pub _markers: *mut _IO_marker, + pub _chain: *mut _IO_FILE, + pub _fileno: ::std::os::raw::c_int, + pub _flags2: ::std::os::raw::c_int, + pub _old_offset: __off_t, + pub _cur_column: ::std::os::raw::c_ushort, + pub _vtable_offset: ::std::os::raw::c_schar, + pub _shortbuf: [::std::os::raw::c_char; 1usize], + pub _lock: *mut _IO_lock_t, + pub _offset: __off64_t, + pub _codecvt: *mut _IO_codecvt, + pub _wide_data: *mut _IO_wide_data, + pub _freeres_list: *mut _IO_FILE, + pub _freeres_buf: *mut ::std::os::raw::c_void, + pub __pad5: usize, + pub _mode: ::std::os::raw::c_int, + pub _unused2: [::std::os::raw::c_char; 20usize], +} pub type zend_long = i64; pub type zend_ulong = u64; -pub type zend_uchar = ::std::os::raw::c_uchar; +pub type zend_off_t = i64; pub const ZEND_RESULT_CODE_SUCCESS: ZEND_RESULT_CODE = 0; pub const ZEND_RESULT_CODE_FAILURE: ZEND_RESULT_CODE = -1; pub type ZEND_RESULT_CODE = ::std::os::raw::c_int; @@ -234,8 +328,8 @@ pub union _zval_struct__bindgen_ty_1 { #[repr(C)] #[derive(Copy, Clone)] pub struct _zval_struct__bindgen_ty_1__bindgen_ty_1 { - pub type_: zend_uchar, - pub type_flags: zend_uchar, + pub type_: u8, + pub type_flags: u8, pub u: _zval_struct__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1, } #[repr(C)] @@ -253,7 +347,7 @@ pub union _zval_struct__bindgen_ty_2 { pub num_args: u32, pub fe_pos: u32, pub fe_iter_idx: u32, - pub property_guard: u32, + pub guard: u32, pub constant_flags: u32, pub extra: u32, } @@ -311,10 +405,10 @@ pub union _zend_array__bindgen_ty_1 { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _zend_array__bindgen_ty_1__bindgen_ty_1 { - pub flags: zend_uchar, - pub _unused: zend_uchar, - pub nIteratorsCount: zend_uchar, - pub _unused2: zend_uchar, + pub flags: u8, + pub _unused: u8, + pub nIteratorsCount: u8, + pub _unused2: u8, } #[repr(C)] #[derive(Copy, Clone)] @@ -329,6 +423,7 @@ pub type HashPosition = u32; pub struct _HashTableIterator { pub ht: *mut HashTable, pub pos: HashPosition, + pub next_copy: u32, } pub type HashTableIterator = _HashTableIterator; #[repr(C)] @@ -386,6 +481,28 @@ extern "C" { extern "C" { pub fn __zend_malloc(len: usize) -> *mut ::std::os::raw::c_void; } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _zend_llist_element { + pub next: *mut _zend_llist_element, + pub prev: *mut _zend_llist_element, + pub data: [::std::os::raw::c_char; 1usize], +} +pub type zend_llist_element = _zend_llist_element; +pub type llist_dtor_func_t = + ::std::option::Option; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _zend_llist { + pub head: *mut zend_llist_element, + pub tail: *mut zend_llist_element, + pub count: usize, + pub size: usize, + pub dtor: llist_dtor_func_t, + pub persistent: ::std::os::raw::c_uchar, + pub traverse_ptr: *mut zend_llist_element, +} +pub type zend_llist = _zend_llist; pub type zend_string_init_interned_func_t = ::std::option::Option< unsafe extern "C" fn( str_: *const ::std::os::raw::c_char, @@ -541,6 +658,25 @@ pub struct _zend_class_arrayaccess_funcs { pub zf_offsetunset: *mut zend_function, } pub type zend_class_arrayaccess_funcs = _zend_class_arrayaccess_funcs; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct stat { + pub st_dev: __dev_t, + pub st_ino: __ino_t, + pub st_nlink: __nlink_t, + pub st_mode: __mode_t, + pub st_uid: __uid_t, + pub st_gid: __gid_t, + pub __pad0: ::std::os::raw::c_int, + pub st_rdev: __dev_t, + pub st_size: __off_t, + pub st_blksize: __blksize_t, + pub st_blocks: __blkcnt_t, + pub st_atim: timespec, + pub st_mtim: timespec, + pub st_ctim: timespec, + pub __glibc_reserved: [__syscall_slong_t; 3usize], +} pub type zend_stream_fsizer_t = ::std::option::Option usize>; pub type zend_stream_reader_t = ::std::option::Option< @@ -568,7 +704,7 @@ pub struct _zend_file_handle { pub handle: _zend_file_handle__bindgen_ty_1, pub filename: *mut zend_string, pub opened_path: *mut zend_string, - pub type_: zend_uchar, + pub type_: u8, pub primary_script: bool, pub in_list: bool, pub buf: *mut ::std::os::raw::c_char, @@ -587,6 +723,7 @@ extern "C" { filename: *const ::std::os::raw::c_char, ); } +pub type zend_stat_t = stat; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _zend_serialize_data { @@ -700,6 +837,7 @@ pub struct _zend_class_entry { pub __debugInfo: *mut zend_function, pub __serialize: *mut zend_function, pub __unserialize: *mut zend_function, + pub default_object_handlers: *const zend_object_handlers, pub iterator_funcs_ptr: *mut zend_class_iterator_funcs, pub arrayaccess_funcs_ptr: *mut zend_class_arrayaccess_funcs, pub __bindgen_anon_2: _zend_class_entry__bindgen_ty_2, @@ -929,7 +1067,7 @@ pub type zend_object_get_gc_t = ::std::option::Option< >; pub type zend_object_do_operation_t = ::std::option::Option< unsafe extern "C" fn( - opcode: zend_uchar, + opcode: u8, result: *mut zval, op1: *mut zval, op2: *mut zval, @@ -996,10 +1134,10 @@ extern "C" { ) -> ::std::os::raw::c_int; } extern "C" { - pub fn zend_is_identical(op1: *mut zval, op2: *mut zval) -> bool; + pub fn zend_is_identical(op1: *const zval, op2: *const zval) -> bool; } extern "C" { - pub fn zend_is_true(op: *mut zval) -> ::std::os::raw::c_int; + pub fn zend_is_true(op: *const zval) -> ::std::os::raw::c_int; } pub type zend_op_array = _zend_op_array; pub type zend_op = _zend_op; @@ -1022,10 +1160,10 @@ pub struct _zend_op { pub result: znode_op, pub extended_value: u32, pub lineno: u32, - pub opcode: zend_uchar, - pub op1_type: zend_uchar, - pub op2_type: zend_uchar, - pub result_type: zend_uchar, + pub opcode: u8, + pub op1_type: u8, + pub op2_type: u8, + pub result_type: u8, } #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -1074,8 +1212,8 @@ pub type zend_arg_info = _zend_arg_info; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _zend_op_array { - pub type_: zend_uchar, - pub arg_flags: [zend_uchar; 3usize], + pub type_: u8, + pub arg_flags: [u8; 3usize], pub fn_flags: u32, pub function_name: *mut zend_string, pub scope: *mut zend_class_entry, @@ -1084,8 +1222,8 @@ pub struct _zend_op_array { pub required_num_args: u32, pub arg_info: *mut zend_arg_info, pub attributes: *mut HashTable, - pub T: u32, pub run_time_cache__ptr: *mut *mut ::std::os::raw::c_void, + pub T: u32, pub cache_size: ::std::os::raw::c_int, pub last_var: ::std::os::raw::c_int, pub last: u32, @@ -1114,8 +1252,8 @@ pub type zif_handler = ::std::option::Option< #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _zend_internal_function { - pub type_: zend_uchar, - pub arg_flags: [zend_uchar; 3usize], + pub type_: u8, + pub arg_flags: [u8; 3usize], pub fn_flags: u32, pub function_name: *mut zend_string, pub scope: *mut zend_class_entry, @@ -1124,8 +1262,8 @@ pub struct _zend_internal_function { pub required_num_args: u32, pub arg_info: *mut zend_internal_arg_info, pub attributes: *mut HashTable, - pub T: u32, pub run_time_cache__ptr: *mut *mut ::std::os::raw::c_void, + pub T: u32, pub handler: zif_handler, pub module: *mut _zend_module_entry, pub reserved: [*mut ::std::os::raw::c_void; 6usize], @@ -1134,7 +1272,7 @@ pub type zend_internal_function = _zend_internal_function; #[repr(C)] #[derive(Copy, Clone)] pub union _zend_function { - pub type_: zend_uchar, + pub type_: u8, pub quick_arg_flags: u32, pub common: _zend_function__bindgen_ty_1, pub op_array: zend_op_array, @@ -1143,8 +1281,8 @@ pub union _zend_function { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _zend_function__bindgen_ty_1 { - pub type_: zend_uchar, - pub arg_flags: [zend_uchar; 3usize], + pub type_: u8, + pub arg_flags: [u8; 3usize], pub fn_flags: u32, pub function_name: *mut zend_string, pub scope: *mut zend_class_entry, @@ -1153,8 +1291,8 @@ pub struct _zend_function__bindgen_ty_1 { pub required_num_args: u32, pub arg_info: *mut zend_arg_info, pub attributes: *mut HashTable, - pub T: u32, pub run_time_cache__ptr: *mut *mut ::std::os::raw::c_void, + pub T: u32, } #[repr(C)] pub struct _zend_execute_data { @@ -1168,7 +1306,15 @@ pub struct _zend_execute_data { pub run_time_cache: *mut *mut ::std::os::raw::c_void, pub extra_named_params: *mut zend_array, } -pub type sigjmp_buf = [::std::os::raw::c_int; 49usize]; +pub type __jmp_buf = [::std::os::raw::c_long; 8usize]; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __jmp_buf_tag { + pub __jmpbuf: __jmp_buf, + pub __mask_was_saved: ::std::os::raw::c_int, + pub __saved_mask: __sigset_t, +} +pub type jmp_buf = [__jmp_buf_tag; 1usize]; pub type zend_executor_globals = _zend_executor_globals; extern "C" { pub static mut executor_globals: zend_executor_globals; @@ -1215,6 +1361,13 @@ pub type zend_objects_store = _zend_objects_store; extern "C" { pub fn zend_objects_store_del(object: *mut zend_object); } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _zend_call_stack { + pub base: *mut ::std::os::raw::c_void, + pub max_size: usize, +} +pub type zend_call_stack = _zend_call_stack; pub type zend_vm_stack = *mut _zend_vm_stack; pub type zend_ini_entry = _zend_ini_entry; #[repr(C)] @@ -1238,7 +1391,7 @@ pub struct _zend_executor_globals { pub symtable_cache_ptr: *mut *mut zend_array, pub symbol_table: zend_array, pub included_files: HashTable, - pub bailout: *mut sigjmp_buf, + pub bailout: *mut jmp_buf, pub error_reporting: ::std::os::raw::c_int, pub exit_status: ::std::os::raw::c_int, pub function_table: *mut HashTable, @@ -1251,29 +1404,32 @@ pub struct _zend_executor_globals { pub current_execute_data: *mut _zend_execute_data, pub fake_scope: *mut zend_class_entry, pub jit_trace_num: u32, - pub precision: zend_long, pub ticks_count: ::std::os::raw::c_int, + pub precision: zend_long, pub persistent_constants_count: u32, pub persistent_functions_count: u32, pub persistent_classes_count: u32, - pub in_autoload: *mut HashTable, - pub full_tables_cleanup: bool, pub no_extensions: bool, + pub full_tables_cleanup: bool, pub vm_interrupt: zend_atomic_bool, pub timed_out: zend_atomic_bool, + pub in_autoload: *mut HashTable, pub hard_timeout: zend_long, + pub stack_base: *mut ::std::os::raw::c_void, + pub stack_limit: *mut ::std::os::raw::c_void, pub regular_list: HashTable, pub persistent_list: HashTable, pub user_error_handler_error_reporting: ::std::os::raw::c_int, + pub exception_ignore_args: bool, pub user_error_handler: zval, pub user_exception_handler: zval, pub user_error_handlers_error_reporting: zend_stack, pub user_error_handlers: zend_stack, pub user_exception_handlers: zend_stack, - pub error_handling: zend_error_handling_t, pub exception_class: *mut zend_class_entry, - pub timeout_seconds: zend_long, + pub error_handling: zend_error_handling_t, pub capture_warnings_during_sccp: ::std::os::raw::c_int, + pub timeout_seconds: zend_long, pub ini_directives: *mut HashTable, pub modified_ini_directives: *mut HashTable, pub error_reporting_ini_entry: *mut zend_ini_entry, @@ -1284,7 +1440,7 @@ pub struct _zend_executor_globals { pub exception_op: [zend_op; 3usize], pub current_module: *mut _zend_module_entry, pub active: bool, - pub flags: zend_uchar, + pub flags: u8, pub assertions: zend_long, pub ht_iterators_count: u32, pub ht_iterators_used: u32, @@ -1294,18 +1450,20 @@ pub struct _zend_executor_globals { pub trampoline: zend_function, pub call_trampoline_op: zend_op, pub weakrefs: HashTable, - pub exception_ignore_args: bool, pub exception_string_param_max_len: zend_long, pub get_gc_buffer: zend_get_gc_buffer, pub main_fiber_context: *mut zend_fiber_context, pub current_fiber_context: *mut zend_fiber_context, pub active_fiber: *mut zend_fiber, - pub fiber_stack_size: zend_long, + pub fiber_stack_size: usize, pub record_errors: bool, pub num_errors: u32, pub errors: *mut *mut zend_error_info, pub filename_override: *mut zend_string, pub lineno_override: zend_long, + pub call_stack: zend_call_stack, + pub max_allowed_stack_size: zend_long, + pub reserved_stack_size: zend_ulong, pub reserved: [*mut ::std::os::raw::c_void; 6usize], } pub type zend_module_entry = _zend_module_entry; @@ -1404,6 +1562,19 @@ pub struct _zend_function_entry { pub flags: u32, } pub type zend_function_entry = _zend_function_entry; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _zend_fcall_info_cache { + pub function_handler: *mut zend_function, + pub calling_scope: *mut zend_class_entry, + pub called_scope: *mut zend_class_entry, + pub object: *mut zend_object, + pub closure: *mut zend_object, +} +pub type zend_fcall_info_cache = _zend_fcall_info_cache; +extern "C" { + pub fn zend_register_module_ex(module: *mut zend_module_entry) -> *mut zend_module_entry; +} extern "C" { pub fn zend_register_internal_class_ex( class_entry: *mut zend_class_entry, @@ -1482,15 +1653,17 @@ pub const _zend_expected_type_Z_EXPECTED_DOUBLE: _zend_expected_type = 20; pub const _zend_expected_type_Z_EXPECTED_DOUBLE_OR_NULL: _zend_expected_type = 21; pub const _zend_expected_type_Z_EXPECTED_NUMBER: _zend_expected_type = 22; pub const _zend_expected_type_Z_EXPECTED_NUMBER_OR_NULL: _zend_expected_type = 23; -pub const _zend_expected_type_Z_EXPECTED_ARRAY_OR_STRING: _zend_expected_type = 24; -pub const _zend_expected_type_Z_EXPECTED_ARRAY_OR_STRING_OR_NULL: _zend_expected_type = 25; -pub const _zend_expected_type_Z_EXPECTED_STRING_OR_LONG: _zend_expected_type = 26; -pub const _zend_expected_type_Z_EXPECTED_STRING_OR_LONG_OR_NULL: _zend_expected_type = 27; -pub const _zend_expected_type_Z_EXPECTED_OBJECT_OR_CLASS_NAME: _zend_expected_type = 28; -pub const _zend_expected_type_Z_EXPECTED_OBJECT_OR_CLASS_NAME_OR_NULL: _zend_expected_type = 29; -pub const _zend_expected_type_Z_EXPECTED_OBJECT_OR_STRING: _zend_expected_type = 30; -pub const _zend_expected_type_Z_EXPECTED_OBJECT_OR_STRING_OR_NULL: _zend_expected_type = 31; -pub const _zend_expected_type_Z_EXPECTED_LAST: _zend_expected_type = 32; +pub const _zend_expected_type_Z_EXPECTED_NUMBER_OR_STRING: _zend_expected_type = 24; +pub const _zend_expected_type_Z_EXPECTED_NUMBER_OR_STRING_OR_NULL: _zend_expected_type = 25; +pub const _zend_expected_type_Z_EXPECTED_ARRAY_OR_STRING: _zend_expected_type = 26; +pub const _zend_expected_type_Z_EXPECTED_ARRAY_OR_STRING_OR_NULL: _zend_expected_type = 27; +pub const _zend_expected_type_Z_EXPECTED_STRING_OR_LONG: _zend_expected_type = 28; +pub const _zend_expected_type_Z_EXPECTED_STRING_OR_LONG_OR_NULL: _zend_expected_type = 29; +pub const _zend_expected_type_Z_EXPECTED_OBJECT_OR_CLASS_NAME: _zend_expected_type = 30; +pub const _zend_expected_type_Z_EXPECTED_OBJECT_OR_CLASS_NAME_OR_NULL: _zend_expected_type = 31; +pub const _zend_expected_type_Z_EXPECTED_OBJECT_OR_STRING: _zend_expected_type = 32; +pub const _zend_expected_type_Z_EXPECTED_OBJECT_OR_STRING_OR_NULL: _zend_expected_type = 33; +pub const _zend_expected_type_Z_EXPECTED_LAST: _zend_expected_type = 34; pub type _zend_expected_type = ::std::os::raw::c_uint; extern "C" { pub fn zend_wrong_parameters_count_error(min_num_args: u32, max_num_args: u32); @@ -1506,6 +1679,418 @@ extern "C" { ... ); } +pub type php_stream = _php_stream; +pub type php_stream_wrapper = _php_stream_wrapper; +pub type php_stream_context = _php_stream_context; +pub type php_stream_filter = _php_stream_filter; +pub type php_stream_notification_func = ::std::option::Option< + unsafe extern "C" fn( + context: *mut php_stream_context, + notifycode: ::std::os::raw::c_int, + severity: ::std::os::raw::c_int, + xmsg: *mut ::std::os::raw::c_char, + xcode: ::std::os::raw::c_int, + bytes_sofar: usize, + bytes_max: usize, + ptr: *mut ::std::os::raw::c_void, + ), +>; +pub type php_stream_notifier = _php_stream_notifier; +#[repr(C)] +pub struct _php_stream_notifier { + pub func: php_stream_notification_func, + pub dtor: ::std::option::Option, + pub ptr: zval, + pub mask: ::std::os::raw::c_int, + pub progress: usize, + pub progress_max: usize, +} +#[repr(C)] +pub struct _php_stream_context { + pub notifier: *mut php_stream_notifier, + pub options: zval, + pub res: *mut zend_resource, +} +pub type php_stream_bucket = _php_stream_bucket; +pub type php_stream_bucket_brigade = _php_stream_bucket_brigade; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_bucket { + pub next: *mut php_stream_bucket, + pub prev: *mut php_stream_bucket, + pub brigade: *mut php_stream_bucket_brigade, + pub buf: *mut ::std::os::raw::c_char, + pub buflen: usize, + pub own_buf: u8, + pub is_persistent: u8, + pub refcount: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_bucket_brigade { + pub head: *mut php_stream_bucket, + pub tail: *mut php_stream_bucket, +} +pub const php_stream_filter_status_t_PSFS_ERR_FATAL: php_stream_filter_status_t = 0; +pub const php_stream_filter_status_t_PSFS_FEED_ME: php_stream_filter_status_t = 1; +pub const php_stream_filter_status_t_PSFS_PASS_ON: php_stream_filter_status_t = 2; +pub type php_stream_filter_status_t = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_filter_ops { + pub filter: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + thisfilter: *mut php_stream_filter, + buckets_in: *mut php_stream_bucket_brigade, + buckets_out: *mut php_stream_bucket_brigade, + bytes_consumed: *mut usize, + flags: ::std::os::raw::c_int, + ) -> php_stream_filter_status_t, + >, + pub dtor: ::std::option::Option, + pub label: *const ::std::os::raw::c_char, +} +pub type php_stream_filter_ops = _php_stream_filter_ops; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_filter_chain { + pub head: *mut php_stream_filter, + pub tail: *mut php_stream_filter, + pub stream: *mut php_stream, +} +pub type php_stream_filter_chain = _php_stream_filter_chain; +#[repr(C)] +pub struct _php_stream_filter { + pub fops: *const php_stream_filter_ops, + pub abstract_: zval, + pub next: *mut php_stream_filter, + pub prev: *mut php_stream_filter, + pub is_persistent: ::std::os::raw::c_int, + pub chain: *mut php_stream_filter_chain, + pub buffer: php_stream_bucket_brigade, + pub res: *mut zend_resource, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_statbuf { + pub sb: zend_stat_t, +} +pub type php_stream_statbuf = _php_stream_statbuf; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_ops { + pub write: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + buf: *const ::std::os::raw::c_char, + count: usize, + ) -> isize, + >, + pub read: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + buf: *mut ::std::os::raw::c_char, + count: usize, + ) -> isize, + >, + pub close: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + close_handle: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + >, + pub flush: ::std::option::Option< + unsafe extern "C" fn(stream: *mut php_stream) -> ::std::os::raw::c_int, + >, + pub label: *const ::std::os::raw::c_char, + pub seek: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + offset: zend_off_t, + whence: ::std::os::raw::c_int, + newoffset: *mut zend_off_t, + ) -> ::std::os::raw::c_int, + >, + pub cast: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + castas: ::std::os::raw::c_int, + ret: *mut *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, + pub stat: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + ssb: *mut php_stream_statbuf, + ) -> ::std::os::raw::c_int, + >, + pub set_option: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + option: ::std::os::raw::c_int, + value: ::std::os::raw::c_int, + ptrparam: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, +} +pub type php_stream_ops = _php_stream_ops; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_wrapper_ops { + pub stream_opener: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + filename: *const ::std::os::raw::c_char, + mode: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + opened_path: *mut *mut zend_string, + context: *mut php_stream_context, + __php_stream_call_depth: ::std::os::raw::c_int, + __zend_filename: *const ::std::os::raw::c_char, + __zend_lineno: u32, + __zend_orig_filename: *const ::std::os::raw::c_char, + __zend_orig_lineno: u32, + ) -> *mut php_stream, + >, + pub stream_closer: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + stream: *mut php_stream, + ) -> ::std::os::raw::c_int, + >, + pub stream_stat: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + stream: *mut php_stream, + ssb: *mut php_stream_statbuf, + ) -> ::std::os::raw::c_int, + >, + pub url_stat: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + flags: ::std::os::raw::c_int, + ssb: *mut php_stream_statbuf, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub dir_opener: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + filename: *const ::std::os::raw::c_char, + mode: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + opened_path: *mut *mut zend_string, + context: *mut php_stream_context, + __php_stream_call_depth: ::std::os::raw::c_int, + __zend_filename: *const ::std::os::raw::c_char, + __zend_lineno: u32, + __zend_orig_filename: *const ::std::os::raw::c_char, + __zend_orig_lineno: u32, + ) -> *mut php_stream, + >, + pub label: *const ::std::os::raw::c_char, + pub unlink: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub rename: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url_from: *const ::std::os::raw::c_char, + url_to: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub stream_mkdir: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + mode: ::std::os::raw::c_int, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub stream_rmdir: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub stream_metadata: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + value: *mut ::std::os::raw::c_void, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, +} +pub type php_stream_wrapper_ops = _php_stream_wrapper_ops; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_wrapper { + pub wops: *const php_stream_wrapper_ops, + pub abstract_: *mut ::std::os::raw::c_void, + pub is_url: ::std::os::raw::c_int, +} +#[repr(C)] +pub struct _php_stream { + pub ops: *const php_stream_ops, + pub abstract_: *mut ::std::os::raw::c_void, + pub readfilters: php_stream_filter_chain, + pub writefilters: php_stream_filter_chain, + pub wrapper: *mut php_stream_wrapper, + pub wrapperthis: *mut ::std::os::raw::c_void, + pub wrapperdata: zval, + pub _bitfield_align_1: [u8; 0], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize]>, + pub mode: [::std::os::raw::c_char; 16usize], + pub flags: u32, + pub res: *mut zend_resource, + pub stdiocast: *mut FILE, + pub orig_path: *mut ::std::os::raw::c_char, + pub ctx: *mut zend_resource, + pub position: zend_off_t, + pub readbuf: *mut ::std::os::raw::c_uchar, + pub readbuflen: usize, + pub readpos: zend_off_t, + pub writepos: zend_off_t, + pub chunk_size: usize, + pub open_filename: *const ::std::os::raw::c_char, + pub open_lineno: u32, + pub enclosing_stream: *mut _php_stream, +} +impl _php_stream { + #[inline] + pub fn is_persistent(&self) -> u16 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u16) } + } + #[inline] + pub fn set_is_persistent(&mut self, val: u16) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 1u8, val as u64) + } + } + #[inline] + pub fn in_free(&self) -> u16 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(1usize, 2u8) as u16) } + } + #[inline] + pub fn set_in_free(&mut self, val: u16) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(1usize, 2u8, val as u64) + } + } + #[inline] + pub fn eof(&self) -> u16 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(3usize, 1u8) as u16) } + } + #[inline] + pub fn set_eof(&mut self, val: u16) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(3usize, 1u8, val as u64) + } + } + #[inline] + pub fn __exposed(&self) -> u16 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 1u8) as u16) } + } + #[inline] + pub fn set___exposed(&mut self, val: u16) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(4usize, 1u8, val as u64) + } + } + #[inline] + pub fn fclose_stdiocast(&self) -> u16 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(5usize, 2u8) as u16) } + } + #[inline] + pub fn set_fclose_stdiocast(&mut self, val: u16) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(5usize, 2u8, val as u64) + } + } + #[inline] + pub fn has_buffered_data(&self) -> u16 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(7usize, 1u8) as u16) } + } + #[inline] + pub fn set_has_buffered_data(&mut self, val: u16) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(7usize, 1u8, val as u64) + } + } + #[inline] + pub fn fclose_stdiocast_flush_in_progress(&self) -> u16 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(8usize, 1u8) as u16) } + } + #[inline] + pub fn set_fclose_stdiocast_flush_in_progress(&mut self, val: u16) { + unsafe { + let val: u16 = ::std::mem::transmute(val); + self._bitfield_1.set(8usize, 1u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1( + is_persistent: u16, + in_free: u16, + eof: u16, + __exposed: u16, + fclose_stdiocast: u16, + has_buffered_data: u16, + fclose_stdiocast_flush_in_progress: u16, + ) -> __BindgenBitfieldUnit<[u8; 2usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize]> = Default::default(); + __bindgen_bitfield_unit.set(0usize, 1u8, { + let is_persistent: u16 = unsafe { ::std::mem::transmute(is_persistent) }; + is_persistent as u64 + }); + __bindgen_bitfield_unit.set(1usize, 2u8, { + let in_free: u16 = unsafe { ::std::mem::transmute(in_free) }; + in_free as u64 + }); + __bindgen_bitfield_unit.set(3usize, 1u8, { + let eof: u16 = unsafe { ::std::mem::transmute(eof) }; + eof as u64 + }); + __bindgen_bitfield_unit.set(4usize, 1u8, { + let __exposed: u16 = unsafe { ::std::mem::transmute(__exposed) }; + __exposed as u64 + }); + __bindgen_bitfield_unit.set(5usize, 2u8, { + let fclose_stdiocast: u16 = unsafe { ::std::mem::transmute(fclose_stdiocast) }; + fclose_stdiocast as u64 + }); + __bindgen_bitfield_unit.set(7usize, 1u8, { + let has_buffered_data: u16 = unsafe { ::std::mem::transmute(has_buffered_data) }; + has_buffered_data as u64 + }); + __bindgen_bitfield_unit.set(8usize, 1u8, { + let fclose_stdiocast_flush_in_progress: u16 = + unsafe { ::std::mem::transmute(fclose_stdiocast_flush_in_progress) }; + fclose_stdiocast_flush_in_progress as u64 + }); + __bindgen_bitfield_unit + } +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _zend_ini_entry_def { @@ -1678,3 +2263,76 @@ extern "C" { extern "C" { pub static mut zend_ce_stringable: *mut zend_class_entry; } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sapi_headers_struct { + pub headers: zend_llist, + pub http_response_code: ::std::os::raw::c_int, + pub send_default_content_type: ::std::os::raw::c_uchar, + pub mimetype: *mut ::std::os::raw::c_char, + pub http_status_line: *mut ::std::os::raw::c_char, +} +pub type sapi_post_entry = _sapi_post_entry; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sapi_request_info { + pub request_method: *const ::std::os::raw::c_char, + pub query_string: *mut ::std::os::raw::c_char, + pub cookie_data: *mut ::std::os::raw::c_char, + pub content_length: zend_long, + pub path_translated: *mut ::std::os::raw::c_char, + pub request_uri: *mut ::std::os::raw::c_char, + pub request_body: *mut _php_stream, + pub content_type: *const ::std::os::raw::c_char, + pub headers_only: bool, + pub no_headers: bool, + pub headers_read: bool, + pub post_entry: *mut sapi_post_entry, + pub content_type_dup: *mut ::std::os::raw::c_char, + pub auth_user: *mut ::std::os::raw::c_char, + pub auth_password: *mut ::std::os::raw::c_char, + pub auth_digest: *mut ::std::os::raw::c_char, + pub argv0: *mut ::std::os::raw::c_char, + pub current_user: *mut ::std::os::raw::c_char, + pub current_user_length: ::std::os::raw::c_int, + pub argc: ::std::os::raw::c_int, + pub argv: *mut *mut ::std::os::raw::c_char, + pub proto_num: ::std::os::raw::c_int, +} +#[repr(C)] +pub struct _sapi_globals_struct { + pub server_context: *mut ::std::os::raw::c_void, + pub request_info: sapi_request_info, + pub sapi_headers: sapi_headers_struct, + pub read_post_bytes: i64, + pub post_read: ::std::os::raw::c_uchar, + pub headers_sent: ::std::os::raw::c_uchar, + pub global_stat: zend_stat_t, + pub default_mimetype: *mut ::std::os::raw::c_char, + pub default_charset: *mut ::std::os::raw::c_char, + pub rfc1867_uploaded_files: *mut HashTable, + pub post_max_size: zend_long, + pub options: ::std::os::raw::c_int, + pub sapi_started: bool, + pub global_request_time: f64, + pub known_post_content_types: HashTable, + pub callback_func: zval, + pub fci_cache: zend_fcall_info_cache, +} +pub type sapi_globals_struct = _sapi_globals_struct; +extern "C" { + pub static mut sapi_globals: sapi_globals_struct; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _sapi_post_entry { + pub content_type: *mut ::std::os::raw::c_char, + pub content_type_len: u32, + pub post_reader: ::std::option::Option, + pub post_handler: ::std::option::Option< + unsafe extern "C" fn( + content_type_dup: *mut ::std::os::raw::c_char, + arg: *mut ::std::os::raw::c_void, + ), + >, +} diff --git a/src/ffi.rs b/src/ffi.rs index a6c3d9486..c658239af 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -26,6 +26,7 @@ extern "C" { pub fn ext_php_rs_zend_object_alloc(obj_size: usize, ce: *mut zend_class_entry) -> *mut c_void; pub fn ext_php_rs_zend_object_release(obj: *mut zend_object); pub fn ext_php_rs_executor_globals() -> *mut zend_executor_globals; + pub fn ext_php_rs_sapi_globals() -> *mut sapi_globals_struct; pub fn ext_php_rs_zend_try_catch( func: unsafe extern "C" fn(*const c_void) -> *const c_void, ctx: *const c_void, diff --git a/src/wrapper.c b/src/wrapper.c index a1fd900ff..a708e57cd 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -40,6 +40,18 @@ zend_executor_globals *ext_php_rs_executor_globals() { #endif } +sapi_globals_struct *ext_php_rs_sapi_globals() { +#ifdef ZTS +#ifdef ZEND_ENABLE_STATIC_TSRMLS_CACHE + return TSRMG_FAST_BULK_STATIC(sapi_globals_offset, sapi_globals_struct); +#else + return TSRMG_FAST_BULK(sapi_globals_offset, sapi_globals_struct *); +#endif +#else + return &sapi_globals; +#endif +} + bool ext_php_rs_zend_try_catch(void* (*callback)(void *), void *ctx, void **result) { zend_try { *result = callback(ctx); diff --git a/src/wrapper.h b/src/wrapper.h index e4e55517c..cb5c6678f 100644 --- a/src/wrapper.h +++ b/src/wrapper.h @@ -21,6 +21,7 @@ #include "zend_inheritance.h" #include "zend_interfaces.h" #include "zend_ini.h" +#include "main/SAPI.h" zend_string *ext_php_rs_zend_string_init(const char *str, size_t len, bool persistent); void ext_php_rs_zend_string_release(zend_string *zs); @@ -30,6 +31,7 @@ void ext_php_rs_set_known_valid_utf8(zend_string *zs); const char *ext_php_rs_php_build_id(); void *ext_php_rs_zend_object_alloc(size_t obj_size, zend_class_entry *ce); void ext_php_rs_zend_object_release(zend_object *obj); -zend_executor_globals *ext_php_rs_executor_globals(); +zend_executor_globals *ext_php_rs_executor_globals();; +sapi_globals_struct *ext_php_rs_sapi_globals(); bool ext_php_rs_zend_try_catch(void* (*callback)(void *), void *ctx, void **result); void ext_php_rs_zend_bailout(); diff --git a/src/zend/globals.rs b/src/zend/globals.rs index 9761ab91d..cbea80a2b 100644 --- a/src/zend/globals.rs +++ b/src/zend/globals.rs @@ -8,12 +8,18 @@ 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, zend_ini_entry}; +use crate::ffi::{ + _sapi_globals_struct, _zend_executor_globals, ext_php_rs_executor_globals, + ext_php_rs_sapi_globals, zend_ini_entry, +}; use crate::types::{ZendHashTable, ZendObject}; /// Stores global variables used in the PHP executor. pub type ExecutorGlobals = _zend_executor_globals; +/// Stores global SAPI variables used in the PHP executor. +pub type SapiGlobals = _sapi_globals_struct; + impl ExecutorGlobals { /// Returns a reference to the PHP executor globals. /// @@ -127,12 +133,52 @@ impl ExecutorGlobals { } } +impl SapiGlobals { + /// Returns a reference to the PHP SAPI globals. + /// + /// The executor globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get() -> GlobalReadGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { ext_php_rs_sapi_globals().as_ref() } + .expect("Static executor globals were invalid"); + let guard = SAPI_LOCK.read(); + GlobalReadGuard { globals, guard } + } + + /// Returns a mutable reference to the PHP executor globals. + /// + /// The executor globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get_mut() -> GlobalWriteGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { ext_php_rs_sapi_globals().as_mut() } + .expect("Static executor globals were invalid"); + let guard = SAPI_LOCK.write(); + GlobalWriteGuard { globals, guard } + } +} + /// Executor globals rwlock. /// /// PHP provides no indication if the executor globals are being accessed so /// this is only effective on the Rust side. static GLOBALS_LOCK: RwLock<()> = const_rwlock(()); +/// SAPI globals rwlock. +/// +/// PHP provides no indication if the executor globals are being accessed so +/// this is only effective on the Rust side. +static SAPI_LOCK: RwLock<()> = const_rwlock(()); + /// Wrapper guard that contains a reference to a given type `T`. Dropping a /// guard releases the lock on the relevant rwlock. pub struct GlobalReadGuard { diff --git a/src/zend/handlers.rs b/src/zend/handlers.rs index 11d220ba0..7e88a7e05 100644 --- a/src/zend/handlers.rs +++ b/src/zend/handlers.rs @@ -238,6 +238,7 @@ impl ZendObjectHandlers { let mut zv = Zval::new(); val.get(self_, &mut zv)?; + #[allow(clippy::unnecessary_mut_passed)] if zend_is_true(&mut zv) == 1 { return Ok(1); } diff --git a/src/zend/mod.rs b/src/zend/mod.rs index af8a5c2d8..67840f908 100644 --- a/src/zend/mod.rs +++ b/src/zend/mod.rs @@ -20,6 +20,7 @@ pub use ex::ExecuteData; pub use function::Function; pub use function::FunctionEntry; pub use globals::ExecutorGlobals; +pub use globals::SapiGlobals; pub use handlers::ZendObjectHandlers; pub use ini_entry_def::IniEntryDef; pub use module::ModuleEntry;