@@ -16,6 +16,7 @@ use crate::types::{ZendObject, Zval};
16
16
use crate :: zend:: ExecutorGlobals ;
17
17
use parking_lot:: { const_rwlock, RwLock } ;
18
18
use std:: ffi:: { c_char, c_void, CString , NulError } ;
19
+ use std:: panic:: { catch_unwind, resume_unwind, RefUnwindSafe } ;
19
20
use std:: path:: Path ;
20
21
use std:: ptr:: null_mut;
21
22
@@ -104,24 +105,41 @@ impl Embed {
104
105
/// assert_eq!(foo.unwrap().string().unwrap(), "foo");
105
106
/// });
106
107
/// ```
107
- pub fn run < F : Fn ( ) > ( func : F ) {
108
+ pub fn run < F : Fn ( ) + RefUnwindSafe > ( func : F ) {
108
109
// @TODO handle php thread safe
109
110
//
110
111
// This is to prevent multiple threads from running php at the same time
111
112
// At some point we should detect if php is compiled with thread safety and avoid doing that in this case
112
113
let _guard = RUN_FN_LOCK . write ( ) ;
113
114
114
- unsafe extern "C" fn wrapper < F : Fn ( ) > ( ctx : * const c_void ) {
115
- ( * ( ctx as * const F ) ) ( ) ;
115
+ unsafe extern "C" fn wrapper < F : Fn ( ) + RefUnwindSafe > ( ctx : * const c_void ) -> * mut c_void {
116
+ // we try to catch panic here so we correctly shutdown php if it happens
117
+ // mandatory when we do assert on test as other test would not run correctly
118
+ let panic = catch_unwind ( || {
119
+ ( * ( ctx as * const F ) ) ( ) ;
120
+ } ) ;
121
+
122
+ let panic_ptr = Box :: into_raw ( Box :: new ( panic) ) ;
123
+
124
+ panic_ptr as * mut c_void
116
125
}
117
126
118
- unsafe {
127
+ let panic = unsafe {
119
128
ext_php_rs_embed_callback (
120
129
0 ,
121
130
null_mut ( ) ,
122
131
wrapper :: < F > ,
123
132
& func as * const F as * const c_void ,
124
- ) ;
133
+ )
134
+ } ;
135
+
136
+ if panic. is_null ( ) {
137
+ return ;
138
+ }
139
+
140
+ if let Err ( err) = unsafe { * Box :: from_raw ( panic as * mut std:: thread:: Result < ( ) > ) } {
141
+ // we resume the panic here so it can be catched correctly by the test framework
142
+ resume_unwind ( err) ;
125
143
}
126
144
}
127
145
@@ -218,4 +236,12 @@ mod tests {
218
236
assert ! ( !result. is_ok( ) ) ;
219
237
} ) ;
220
238
}
239
+
240
+ #[ test]
241
+ #[ should_panic]
242
+ fn test_panic ( ) {
243
+ Embed :: run ( || {
244
+ panic ! ( "test panic" ) ;
245
+ } ) ;
246
+ }
221
247
}
0 commit comments