ext_php_rs/zend/
module.rs1use std::cell::UnsafeCell;
5use std::ffi::CString;
6use std::mem::MaybeUninit;
7use std::os::raw::c_char;
8use std::ptr;
9use std::sync::Once;
10
11use crate::ffi::zend_module_entry;
12
13fn zend_type_has_name(type_mask: u32) -> bool {
14 cfg_if::cfg_if! {
15 if #[cfg(php83)] {
16 (type_mask & crate::ffi::_ZEND_TYPE_LITERAL_NAME_BIT) != 0
17 } else {
18 (type_mask & crate::ffi::_ZEND_TYPE_NAME_BIT) != 0
19 }
20 }
21}
22
23pub type ModuleEntry = zend_module_entry;
25
26impl ModuleEntry {
27 #[deprecated(note = "use StaticModuleEntry to avoid leaking the allocation")]
30 #[must_use]
31 pub fn into_raw(self) -> *mut Self {
32 Box::into_raw(Box::new(self))
33 }
34}
35
36pub struct StaticModuleEntry {
42 init: Once,
43 inner: UnsafeCell<MaybeUninit<ModuleEntry>>,
44}
45
46unsafe impl Sync for StaticModuleEntry {}
47
48impl Default for StaticModuleEntry {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl StaticModuleEntry {
55 #[must_use]
57 pub const fn new() -> Self {
58 Self {
59 init: Once::new(),
60 inner: UnsafeCell::new(MaybeUninit::uninit()),
61 }
62 }
63
64 pub fn get_or_init(&self, f: impl FnOnce() -> ModuleEntry) -> *mut ModuleEntry {
68 self.init.call_once(|| unsafe {
69 (*self.inner.get()).write(f());
70 });
71 unsafe { (*self.inner.get()).as_mut_ptr() }
72 }
73}
74
75pub unsafe fn cleanup_module_allocations(entry: *mut ModuleEntry) {
87 let entry = unsafe { &mut *entry };
88
89 if !entry.name.is_null() {
90 unsafe { drop(CString::from_raw(entry.name.cast_mut())) };
91 entry.name = ptr::null();
92 }
93 if !entry.version.is_null() {
94 unsafe { drop(CString::from_raw(entry.version.cast_mut())) };
95 entry.version = ptr::null();
96 }
97
98 if entry.functions.is_null() {
99 return;
100 }
101
102 let funcs = entry.functions.cast_mut();
103 let mut count: usize = 0;
104
105 while !unsafe { (*funcs.add(count)).fname }.is_null() {
106 let func = unsafe { &mut *funcs.add(count) };
107
108 unsafe { drop(CString::from_raw(func.fname.cast_mut())) };
109 func.fname = ptr::null();
110
111 if !func.arg_info.is_null() {
113 let n = func.num_args as usize;
114 let base = func.arg_info.cast_mut();
115
116 for i in 0..=n {
117 let arg = unsafe { &mut *base.add(i) };
118
119 if i > 0 && !arg.name.is_null() {
120 unsafe { drop(CString::from_raw(arg.name.cast_mut())) };
121 }
122 if !arg.default_value.is_null() {
123 unsafe { drop(CString::from_raw(arg.default_value.cast_mut())) };
124 }
125 if !arg.type_.ptr.is_null() && zend_type_has_name(arg.type_.type_mask) {
126 unsafe { drop(CString::from_raw(arg.type_.ptr.cast::<c_char>())) };
127 }
128 }
129
130 unsafe { drop(Box::from_raw(ptr::slice_from_raw_parts_mut(base, n + 1))) };
131 }
132
133 count += 1;
134 }
135
136 unsafe {
137 drop(Box::from_raw(ptr::slice_from_raw_parts_mut(
138 funcs,
139 count + 1,
140 )));
141 }
142 entry.functions = ptr::null();
143}