mirror of
https://github.com/danog/ext-php-rs.git
synced 2024-12-02 09:37:51 +01:00
feat(sapi): split try_catch / try_catch_first, global feature for test
This commit is contained in:
parent
4f74bfcd8a
commit
411ee6c176
@ -90,7 +90,7 @@ impl Embed {
|
||||
zend_stream_init_filename(&mut file_handle, path.as_ptr());
|
||||
}
|
||||
|
||||
let exec_result = try_catch(|| unsafe { php_execute_script(&mut file_handle) }, false);
|
||||
let exec_result = try_catch(|| unsafe { php_execute_script(&mut file_handle) });
|
||||
|
||||
match exec_result {
|
||||
Err(_) => Err(EmbedError::CatchError),
|
||||
@ -184,16 +184,13 @@ impl Embed {
|
||||
|
||||
let mut result = Zval::new();
|
||||
|
||||
let exec_result = try_catch(
|
||||
|| unsafe {
|
||||
zend_eval_string(
|
||||
cstr.as_ptr() as *const c_char,
|
||||
&mut result,
|
||||
b"run\0".as_ptr() as *const _,
|
||||
)
|
||||
},
|
||||
false,
|
||||
);
|
||||
let exec_result = try_catch(|| unsafe {
|
||||
zend_eval_string(
|
||||
cstr.as_ptr() as *const c_char,
|
||||
&mut result,
|
||||
b"run\0".as_ptr() as *const _,
|
||||
)
|
||||
});
|
||||
|
||||
match exec_result {
|
||||
Err(_) => Err(EmbedError::CatchError),
|
||||
|
@ -25,7 +25,7 @@ pub use ini_entry_def::IniEntryDef;
|
||||
pub use module::ModuleEntry;
|
||||
#[cfg(feature = "embed")]
|
||||
pub(crate) use try_catch::panic_wrapper;
|
||||
pub use try_catch::{bailout, try_catch};
|
||||
pub use try_catch::{bailout, try_catch, try_catch_first};
|
||||
|
||||
// Used as the format string for `php_printf`.
|
||||
const FORMAT_STR: &[u8] = b"%s\0";
|
||||
|
@ -28,10 +28,28 @@ pub(crate) unsafe extern "C" fn panic_wrapper<R, F: FnMut() -> R + RefUnwindSafe
|
||||
///
|
||||
/// * `Ok(R)` - The result of the function
|
||||
/// * `Err(CatchError)` - A bailout occurred during the execution
|
||||
pub fn try_catch<R, F: FnMut() -> R + RefUnwindSafe>(
|
||||
func: F,
|
||||
first: bool,
|
||||
) -> Result<R, CatchError> {
|
||||
pub fn try_catch<R, F: FnMut() -> R + RefUnwindSafe>(func: F) -> Result<R, CatchError> {
|
||||
do_try_catch(func, false)
|
||||
}
|
||||
|
||||
/// PHP propose a try catch mechanism in C using setjmp and longjmp (bailout)
|
||||
/// It store the arg of setjmp into the bailout field of the global executor
|
||||
/// If a bailout is triggered, the executor will jump to the setjmp and restore the previous setjmp
|
||||
///
|
||||
/// try_catch_first allow to use this mechanism
|
||||
///
|
||||
/// This functions differs from ['try_catch'] as it also initialize the bailout mechanism
|
||||
/// for the first time
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Ok(R)` - The result of the function
|
||||
/// * `Err(CatchError)` - A bailout occurred during the execution
|
||||
pub fn try_catch_first<R, F: FnMut() -> R + RefUnwindSafe>(func: F) -> Result<R, CatchError> {
|
||||
do_try_catch(func, true)
|
||||
}
|
||||
|
||||
fn do_try_catch<R, F: FnMut() -> R + RefUnwindSafe>(func: F, first: bool) -> Result<R, CatchError> {
|
||||
let mut panic_ptr = null_mut();
|
||||
let has_bailout = unsafe {
|
||||
if first {
|
||||
@ -91,19 +109,16 @@ mod tests {
|
||||
#[test]
|
||||
fn test_catch() {
|
||||
Embed::run(|| {
|
||||
let catch = try_catch(
|
||||
|| {
|
||||
unsafe {
|
||||
bailout();
|
||||
}
|
||||
let catch = try_catch(|| {
|
||||
unsafe {
|
||||
bailout();
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
{
|
||||
assert!(false);
|
||||
}
|
||||
},
|
||||
false,
|
||||
);
|
||||
#[allow(unreachable_code)]
|
||||
{
|
||||
assert!(false);
|
||||
}
|
||||
});
|
||||
|
||||
assert!(catch.is_err());
|
||||
});
|
||||
@ -112,12 +127,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_no_catch() {
|
||||
Embed::run(|| {
|
||||
let catch = try_catch(
|
||||
|| {
|
||||
assert!(true);
|
||||
},
|
||||
false,
|
||||
);
|
||||
let catch = try_catch(|| {
|
||||
assert!(true);
|
||||
});
|
||||
|
||||
assert!(catch.is_ok());
|
||||
});
|
||||
@ -141,24 +153,18 @@ mod tests {
|
||||
#[should_panic]
|
||||
fn test_panic() {
|
||||
Embed::run(|| {
|
||||
let _ = try_catch(
|
||||
|| {
|
||||
panic!("should panic");
|
||||
},
|
||||
false,
|
||||
);
|
||||
let _ = try_catch(|| {
|
||||
panic!("should panic");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_return() {
|
||||
let foo = Embed::run(|| {
|
||||
let result = try_catch(
|
||||
|| {
|
||||
return "foo";
|
||||
},
|
||||
false,
|
||||
);
|
||||
let result = try_catch(|| {
|
||||
return "foo";
|
||||
});
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
@ -172,17 +178,14 @@ mod tests {
|
||||
fn test_memory_leak() {
|
||||
let mut ptr = null_mut();
|
||||
|
||||
let _ = try_catch(
|
||||
|| {
|
||||
let mut result = "foo".to_string();
|
||||
ptr = &mut result;
|
||||
let _ = try_catch(|| {
|
||||
let mut result = "foo".to_string();
|
||||
ptr = &mut result;
|
||||
|
||||
unsafe {
|
||||
bailout();
|
||||
}
|
||||
},
|
||||
false,
|
||||
);
|
||||
unsafe {
|
||||
bailout();
|
||||
}
|
||||
});
|
||||
|
||||
// Check that the string is never released
|
||||
let result = unsafe { &*ptr as &str };
|
||||
|
@ -1,14 +1,12 @@
|
||||
#![cfg_attr(windows, feature(abi_vectorcall))]
|
||||
#![cfg(feature = "embed")]
|
||||
extern crate ext_php_rs;
|
||||
|
||||
#[cfg(feature = "embed")]
|
||||
use ext_php_rs::embed::Embed;
|
||||
#[cfg(feature = "embed")]
|
||||
use ext_php_rs::ffi::zend_register_module_ex;
|
||||
use ext_php_rs::prelude::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "embed")]
|
||||
fn test_module() {
|
||||
Embed::run(|| {
|
||||
// Allow to load the module
|
||||
|
@ -1,25 +1,19 @@
|
||||
#![cfg_attr(windows, feature(abi_vectorcall))]
|
||||
#![cfg(feature = "embed")]
|
||||
extern crate ext_php_rs;
|
||||
|
||||
#[cfg(feature = "embed")]
|
||||
use std::ffi::c_char;
|
||||
#[cfg(feature = "embed")]
|
||||
use ext_php_rs::builders::SapiBuilder;
|
||||
#[cfg(feature = "embed")]
|
||||
use ext_php_rs::embed::{ext_php_rs_sapi_startup, Embed};
|
||||
#[cfg(feature = "embed")]
|
||||
use ext_php_rs::ffi::{
|
||||
php_module_shutdown, php_module_startup, php_request_shutdown, php_request_startup,
|
||||
sapi_shutdown, sapi_startup, ZEND_RESULT_CODE_SUCCESS,
|
||||
};
|
||||
use ext_php_rs::prelude::*;
|
||||
#[cfg(feature = "embed")]
|
||||
use ext_php_rs::zend::try_catch;
|
||||
use ext_php_rs::zend::try_catch_first;
|
||||
use std::ffi::c_char;
|
||||
|
||||
#[cfg(feature = "embed")]
|
||||
static mut LAST_OUTPUT: String = String::new();
|
||||
|
||||
#[cfg(feature = "embed")]
|
||||
extern "C" fn output_tester(str: *const c_char, str_length: usize) -> usize {
|
||||
let char = unsafe { std::slice::from_raw_parts(str as *const u8, str_length) };
|
||||
let string = String::from_utf8_lossy(char);
|
||||
@ -34,7 +28,6 @@ extern "C" fn output_tester(str: *const c_char, str_length: usize) -> usize {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "embed")]
|
||||
fn test_sapi() {
|
||||
let mut builder = SapiBuilder::new("test", "Test");
|
||||
builder = builder.ub_write_function(output_tester);
|
||||
@ -58,26 +51,23 @@ fn test_sapi() {
|
||||
|
||||
assert_eq!(result, ZEND_RESULT_CODE_SUCCESS);
|
||||
|
||||
let _ = try_catch(
|
||||
|| {
|
||||
let result = Embed::eval("$foo = hello_world('foo');");
|
||||
let _ = try_catch_first(|| {
|
||||
let result = Embed::eval("$foo = hello_world('foo');");
|
||||
|
||||
assert!(result.is_ok());
|
||||
assert!(result.is_ok());
|
||||
|
||||
let zval = result.unwrap();
|
||||
let zval = result.unwrap();
|
||||
|
||||
assert!(zval.is_string());
|
||||
assert!(zval.is_string());
|
||||
|
||||
let string = zval.string().unwrap();
|
||||
let string = zval.string().unwrap();
|
||||
|
||||
assert_eq!(string.to_string(), "Hello, foo!");
|
||||
assert_eq!(string.to_string(), "Hello, foo!");
|
||||
|
||||
let result = Embed::eval("var_dump($foo);");
|
||||
let result = Embed::eval("var_dump($foo);");
|
||||
|
||||
assert!(result.is_ok());
|
||||
},
|
||||
true,
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
});
|
||||
|
||||
unsafe {
|
||||
php_request_shutdown(std::ptr::null_mut());
|
||||
|
Loading…
Reference in New Issue
Block a user