@@ -34,21 +34,11 @@ pub struct ZendMMState {
3434 /// The engine's previous custom shutdown function, if there is one.
3535 prev_custom_mm_shutdown : Option < zend:: VmMmCustomShutdownFn > ,
3636 /// Safety: this function pointer is only allowed to point to
37- /// `alloc_prof_prev_alloc()` when at the same time the
38- /// `ZEND_MM_STATE.prev_custom_mm_alloc` is initialised to a valid function
39- /// pointer, otherwise there will be dragons.
40- alloc : unsafe fn ( size_t ) -> * mut c_void ,
41- /// Safety: this function pointer is only allowed to point to
4237 /// `alloc_prof_prev_realloc()` when at the same time the
4338 /// `ZEND_MM_STATE.prev_custom_mm_realloc` is initialised to a valid
4439 /// function pointer, otherwise there will be dragons.
4540 realloc : unsafe fn ( * mut c_void , size_t ) -> * mut c_void ,
4641 /// Safety: this function pointer is only allowed to point to
47- /// `alloc_prof_prev_free()` when at the same time the
48- /// `ZEND_MM_STATE.prev_custom_mm_free` is initialised to a valid function
49- /// pointer, otherwise there will be dragons.
50- free : unsafe fn ( * mut c_void ) ,
51- /// Safety: this function pointer is only allowed to point to
5242 /// `alloc_prof_prev_gc()` when at the same time the
5343 /// `ZEND_MM_STATE.prev_custom_mm_gc` is initialised to a valid function
5444 /// pointer, otherwise there will be dragons.
@@ -78,9 +68,7 @@ impl ZendMMState {
7868 prev_custom_mm_free : None ,
7969 prev_custom_mm_gc : None ,
8070 prev_custom_mm_shutdown : None ,
81- alloc : super :: alloc_prof_panic_alloc,
8271 realloc : super :: alloc_prof_panic_realloc,
83- free : super :: alloc_prof_panic_free,
8472 gc : alloc_prof_panic_gc,
8573 shutdown : alloc_prof_panic_shutdown,
8674 }
@@ -127,14 +115,10 @@ pub fn alloc_prof_rinit(heap_live_enabled: bool) {
127115 ptr:: addr_of_mut!( zend_mm_state. prev_custom_mm_shutdown) ,
128116 ) ;
129117 }
130- zend_mm_state. alloc = alloc_prof_prev_alloc;
131- zend_mm_state. free = alloc_prof_prev_free;
132118 zend_mm_state. realloc = alloc_prof_prev_realloc;
133119 zend_mm_state. gc = alloc_prof_prev_gc;
134120 zend_mm_state. shutdown = alloc_prof_prev_shutdown;
135121 } else {
136- zend_mm_state. alloc = alloc_prof_orig_alloc;
137- zend_mm_state. free = alloc_prof_orig_free;
138122 zend_mm_state. realloc = alloc_prof_orig_realloc;
139123 zend_mm_state. gc = alloc_prof_orig_gc;
140124 zend_mm_state. shutdown = alloc_prof_orig_shutdown;
@@ -303,7 +287,7 @@ unsafe fn alloc_prof_malloc_impl(len: size_t) -> *mut c_void {
303287 #[ cfg( feature = "debug_stats" ) ]
304288 ALLOCATION_PROFILING_SIZE . fetch_add ( len as u64 , Relaxed ) ;
305289
306- let ptr = tls_zend_mm_state_get ! ( alloc ) ( len) ;
290+ let ptr = alloc_prof_forward_alloc ( len) ;
307291
308292 // during startup, minit, rinit, ... current_execute_data is null
309293 // we are only interested in allocations during userland operations
@@ -318,27 +302,19 @@ unsafe fn alloc_prof_malloc_impl(len: size_t) -> *mut c_void {
318302 ptr
319303}
320304
321- unsafe fn alloc_prof_prev_alloc ( len : size_t ) -> * mut c_void {
322- // Safety: `ZEND_MM_STATE.prev_custom_mm_alloc` will be initialised in
323- // `alloc_prof_rinit()` and only point to this function when
324- // `prev_custom_mm_alloc` is also initialised.
325- // Note: We use `.unwrap()` instead of `.unwrap_unchecked()` here because a
326- // neighboring extension could misbehave. If that happens, we want a proper
327- // panic with backtrace for debugging rather than undefined behavior.
328- let alloc = tls_zend_mm_state_get ! ( prev_custom_mm_alloc) . unwrap ( ) ;
329- #[ cfg( php_debug) ]
330- {
331- alloc ( len, ptr:: null ( ) , 0 , ptr:: null ( ) , 0 )
305+ #[ inline( always) ]
306+ unsafe fn alloc_prof_forward_alloc ( len : size_t ) -> * mut c_void {
307+ let state = tls_zend_mm_state_copy ! ( ) ;
308+ if let Some ( alloc) = state. prev_custom_mm_alloc {
309+ #[ cfg( php_debug) ]
310+ return alloc ( len, ptr:: null ( ) , 0 , ptr:: null ( ) , 0 ) ;
311+ #[ cfg( not( php_debug) ) ]
312+ return alloc ( len) ;
332313 }
333- #[ cfg( not( php_debug) ) ]
334- alloc ( len)
335- }
336314
337- unsafe fn alloc_prof_orig_alloc ( len : size_t ) -> * mut c_void {
338- // Safety: `ZEND_MM_STATE.heap` will be initialised in `alloc_prof_rinit()` and custom ZendMM
339- // handlers only point to this function after successful init. Using `unwrap_unchecked()` is
340- // safe here as we have full control over ZendMM with no neighboring extensions.
341- let heap = tls_zend_mm_state_get ! ( heap) . unwrap_unchecked ( ) ;
315+ let Some ( heap) = state. heap else {
316+ super :: initialization_panic ( ) ;
317+ } ;
342318 #[ cfg( php_debug) ]
343319 return zend:: _zend_mm_alloc ( heap, len, ptr:: null ( ) , 0 , ptr:: null ( ) , 0 ) ;
344320 #[ cfg( not( php_debug) ) ]
@@ -375,7 +351,7 @@ fn alloc_prof_free_handler(heap_live_enabled: bool) -> zend::VmMmCustomFreeFn {
375351
376352#[ cfg( not( php_debug) ) ]
377353unsafe extern "C" fn alloc_prof_free_noop ( ptr : * mut c_void ) {
378- tls_zend_mm_state_get ! ( free ) ( ptr) ;
354+ alloc_prof_forward_free ( ptr) ;
379355}
380356
381357#[ cfg( php_debug) ]
@@ -386,7 +362,7 @@ unsafe extern "C" fn alloc_prof_free_noop(
386362 _orig_file : * const c_char ,
387363 _orig_line : c_uint ,
388364) {
389- tls_zend_mm_state_get ! ( free ) ( ptr) ;
365+ alloc_prof_forward_free ( ptr) ;
390366}
391367
392368#[ inline( always) ]
@@ -395,30 +371,22 @@ unsafe fn alloc_prof_free_impl(ptr: *mut c_void) {
395371 if !ptr. is_null ( ) {
396372 untrack_allocation ( ptr) ;
397373 }
398- tls_zend_mm_state_get ! ( free ) ( ptr) ;
374+ alloc_prof_forward_free ( ptr) ;
399375}
400376
401- unsafe fn alloc_prof_prev_free ( ptr : * mut c_void ) {
402- // Safety: `ZEND_MM_STATE.prev_custom_mm_free` will be initialised in
403- // `alloc_prof_rinit()` and only point to this function when
404- // `prev_custom_mm_free` is also initialised.
405- // Note: We use `.unwrap()` instead of `.unwrap_unchecked()` here because a
406- // neighboring extension could misbehave. If that happens, we want a proper
407- // panic with backtrace for debugging rather than undefined behavior.
408- let free = tls_zend_mm_state_get ! ( prev_custom_mm_free) . unwrap ( ) ;
409- #[ cfg( php_debug) ]
410- {
411- free ( ptr, core:: ptr:: null ( ) , 0 , core:: ptr:: null ( ) , 0 )
377+ #[ inline( always) ]
378+ unsafe fn alloc_prof_forward_free ( ptr : * mut c_void ) {
379+ let state = tls_zend_mm_state_copy ! ( ) ;
380+ if let Some ( free) = state. prev_custom_mm_free {
381+ #[ cfg( php_debug) ]
382+ return free ( ptr, core:: ptr:: null ( ) , 0 , core:: ptr:: null ( ) , 0 ) ;
383+ #[ cfg( not( php_debug) ) ]
384+ return free ( ptr) ;
412385 }
413- #[ cfg( not( php_debug) ) ]
414- free ( ptr)
415- }
416386
417- unsafe fn alloc_prof_orig_free ( ptr : * mut c_void ) {
418- // Safety: `ZEND_MM_STATE.heap` will be initialised in `alloc_prof_rinit()` and custom ZendMM
419- // handlers only point to this function after successful init. Using `unwrap_unchecked()` is
420- // safe here as we have full control over ZendMM with no neighboring extensions.
421- let heap = tls_zend_mm_state_get ! ( heap) . unwrap_unchecked ( ) ;
387+ let Some ( heap) = state. heap else {
388+ super :: initialization_panic ( ) ;
389+ } ;
422390 #[ cfg( php_debug) ]
423391 return zend:: _zend_mm_free ( heap, ptr, core:: ptr:: null ( ) , 0 , core:: ptr:: null ( ) , 0 ) ;
424392 #[ cfg( not( php_debug) ) ]
0 commit comments