Skip to content

Commit aebb43a

Browse files
authored
feat(alloc): add estrdup
This adds estrdup to alloc. This is needed with SAPI when ZTS is enabled as file_handles need their input path to be allocated in the PHP memory manager. Refs: #444
1 parent 5bb712a commit aebb43a

File tree

3 files changed

+79
-2
lines changed

3 files changed

+79
-2
lines changed

allowed_bindings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ bind! {
2727
_call_user_function_impl,
2828
_efree,
2929
_emalloc,
30+
_estrdup,
3031
_zend_executor_globals,
3132
_zend_compiler_globals,
3233
_sapi_globals_struct,

docsrs_bindings.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,15 @@ extern "C" {
491491
__zend_orig_lineno: u32,
492492
);
493493
}
494+
extern "C" {
495+
pub fn _estrdup(
496+
s: *const ::std::os::raw::c_char,
497+
__zend_filename: *const ::std::os::raw::c_char,
498+
__zend_lineno: u32,
499+
__zend_orig_filename: *const ::std::os::raw::c_char,
500+
__zend_orig_lineno: u32,
501+
) -> *mut ::std::os::raw::c_char;
502+
}
494503
extern "C" {
495504
pub fn __zend_malloc(len: usize) -> *mut ::std::os::raw::c_void;
496505
}

src/alloc.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
44
use cfg_if::cfg_if;
55

6-
use crate::ffi::{_efree, _emalloc};
7-
use std::{alloc::Layout, ffi::c_void};
6+
use crate::ffi::{_efree, _emalloc, _estrdup};
7+
use std::{
8+
alloc::Layout,
9+
ffi::{c_char, c_void, CString},
10+
};
811

912
/// Uses the PHP memory allocator to allocate request-bound memory.
1013
///
@@ -62,3 +65,67 @@ pub unsafe fn efree(ptr: *mut u8) {
6265
}
6366
}
6467
}
68+
69+
/// Duplicates a string using the PHP memory manager.
70+
///
71+
/// # Parameters
72+
///
73+
/// * `string` - The string to duplicate, which can be any type that can be
74+
/// converted into a `Vec<u8>`.
75+
///
76+
/// # Returns
77+
///
78+
/// A pointer to the duplicated string in the PHP memory manager.
79+
pub fn estrdup(string: impl Into<Vec<u8>>) -> *mut c_char {
80+
let string = unsafe { CString::from_vec_unchecked(string.into()) }.into_raw();
81+
82+
let result = unsafe {
83+
cfg_if! {
84+
if #[cfg(php_debug)] {
85+
#[allow(clippy::used_underscore_items)]
86+
_estrdup(string, std::ptr::null_mut(), 0, std::ptr::null_mut(), 0)
87+
} else {
88+
#[allow(clippy::used_underscore_items)]
89+
_estrdup(string)
90+
}
91+
}
92+
};
93+
94+
drop(unsafe { CString::from_raw(string) });
95+
result
96+
}
97+
98+
#[cfg(test)]
99+
#[cfg(feature = "embed")]
100+
mod test {
101+
use super::*;
102+
use crate::embed::Embed;
103+
use std::ffi::CStr;
104+
105+
#[test]
106+
fn test_emalloc() {
107+
Embed::run(|| {
108+
let layout = Layout::from_size_align(16, 8).expect("should create layout");
109+
let ptr = emalloc(layout);
110+
assert!(!ptr.is_null());
111+
unsafe { efree(ptr) };
112+
});
113+
}
114+
115+
#[test]
116+
fn test_estrdup() {
117+
Embed::run(|| {
118+
let original = "Hello, world!";
119+
let duplicated = estrdup(original);
120+
assert!(!duplicated.is_null());
121+
122+
let duplicated_str = unsafe { CStr::from_ptr(duplicated) };
123+
assert_eq!(
124+
duplicated_str.to_str().expect("should convert to str"),
125+
original
126+
);
127+
128+
unsafe { efree(duplicated.cast::<u8>()) }
129+
});
130+
}
131+
}

0 commit comments

Comments
 (0)