@@ -517,28 +517,97 @@ static bool has_opline(zend_execute_data *execute_data)
517
517
;
518
518
}
519
519
520
+ // When a custom memory manager is installed, ZendMM alters its behaviour. For
521
+ // example `zend_mm_gc()` will not do anything anymore, or `zend_mm_shutdown()`
522
+ // won't cleanup chunks and leak memory. This might not be a problem in tests,
523
+ // but I fear folks might see and use this implementation as a boiler plate when
524
+ // trying to use this hook
525
+ int zend_test_prepare_zendmm_for_call (zend_mm_heap * heap )
526
+ {
527
+ int flag = 0 ;
528
+ memcpy (& flag , heap , sizeof (int ));
529
+ int new_flag = 0 ;
530
+ memcpy (heap , & new_flag , sizeof (int ));
531
+ return flag ;
532
+ }
533
+
534
+ void zend_test_restore_zendmm_after_call (zend_mm_heap * heap , int flag )
535
+ {
536
+ memcpy (heap , & flag , sizeof (int ));
537
+ }
538
+
520
539
void * zend_test_custom_malloc (size_t len )
521
540
{
522
541
if (has_opline (EG (current_execute_data ))) {
523
542
assert (EG (current_execute_data )-> opline -> lineno != (uint32_t )-1 );
524
543
}
525
- return _zend_mm_alloc (ZT_G (zend_orig_heap ), len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC );
544
+ if (ZT_G (zendmm_orig_malloc )) {
545
+ return ZT_G (zendmm_orig_malloc )(len );
546
+ }
547
+ int flag = zend_test_prepare_zendmm_for_call (zend_mm_get_heap ());
548
+ void * ptr = _zend_mm_alloc (zend_mm_get_heap (), len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC );
549
+ zend_test_restore_zendmm_after_call (zend_mm_get_heap (), flag );
550
+ return ptr ;
526
551
}
527
552
528
553
void zend_test_custom_free (void * ptr )
529
554
{
530
555
if (has_opline (EG (current_execute_data ))) {
531
556
assert (EG (current_execute_data )-> opline -> lineno != (uint32_t )-1 );
532
557
}
533
- _zend_mm_free (ZT_G (zend_orig_heap ), ptr ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC );
558
+ if (ZT_G (zendmm_orig_free )) {
559
+ ZT_G (zendmm_orig_free )(ptr );
560
+ return ;
561
+ }
562
+ int flag = zend_test_prepare_zendmm_for_call (zend_mm_get_heap ());
563
+ _zend_mm_free (zend_mm_get_heap (), ptr ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC );
564
+ zend_test_restore_zendmm_after_call (zend_mm_get_heap (), flag );
534
565
}
535
566
536
567
void * zend_test_custom_realloc (void * ptr , size_t len )
537
568
{
538
569
if (has_opline (EG (current_execute_data ))) {
539
570
assert (EG (current_execute_data )-> opline -> lineno != (uint32_t )-1 );
540
571
}
541
- return _zend_mm_realloc (ZT_G (zend_orig_heap ), ptr , len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC );
572
+ if (ZT_G (zendmm_orig_realloc )) {
573
+ return ZT_G (zendmm_orig_realloc )(ptr , len );
574
+ }
575
+ int flag = zend_test_prepare_zendmm_for_call (zend_mm_get_heap ());
576
+ void * new_ptr = _zend_mm_realloc (zend_mm_get_heap (), ptr , len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC );
577
+ zend_test_restore_zendmm_after_call (zend_mm_get_heap (), flag );
578
+ return new_ptr ;
579
+ }
580
+
581
+ void zend_test_install_custom_mm_handler (void )
582
+ {
583
+ // fetch maybe installed previous handlers
584
+ if (!is_zend_mm ()) {
585
+ zend_mm_get_custom_handlers (
586
+ zend_mm_get_heap (),
587
+ & ZT_G (zendmm_orig_malloc ),
588
+ & ZT_G (zendmm_orig_free ),
589
+ & ZT_G (zendmm_orig_realloc )
590
+ );
591
+ }
592
+ zend_mm_set_custom_handlers (
593
+ zend_mm_get_heap (),
594
+ zend_test_custom_malloc ,
595
+ zend_test_custom_free ,
596
+ zend_test_custom_realloc
597
+ );
598
+ }
599
+
600
+ void zend_test_uninstall_custom_mm_handler (void )
601
+ {
602
+ ZT_G (zendmm_orig_malloc ) = NULL ;
603
+ ZT_G (zendmm_orig_free ) = NULL ;
604
+ ZT_G (zendmm_orig_realloc ) = NULL ;
605
+ zend_mm_set_custom_handlers (
606
+ zend_mm_get_heap (),
607
+ NULL ,
608
+ NULL ,
609
+ NULL
610
+ );
542
611
}
543
612
544
613
static PHP_INI_MH (OnUpdateZendTestObserveOplineInZendMM )
@@ -550,22 +619,9 @@ static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)
550
619
int int_value = zend_ini_parse_bool (new_value );
551
620
552
621
if (int_value == 1 ) {
553
- // `zend_mm_heap` is a private struct, so we have not way to find the
554
- // actual size, but 4096 bytes should be enough
555
- ZT_G (zend_test_heap ) = malloc (4096 );
556
- memset (ZT_G (zend_test_heap ), 0 , 4096 );
557
- zend_mm_set_custom_handlers (
558
- ZT_G (zend_test_heap ),
559
- zend_test_custom_malloc ,
560
- zend_test_custom_free ,
561
- zend_test_custom_realloc
562
- );
563
- ZT_G (zend_orig_heap ) = zend_mm_get_heap ();
564
- zend_mm_set_heap (ZT_G (zend_test_heap ));
565
- } else if (ZT_G (zend_test_heap )) {
566
- free (ZT_G (zend_test_heap ));
567
- ZT_G (zend_test_heap ) = NULL ;
568
- zend_mm_set_heap (ZT_G (zend_orig_heap ));
622
+ zend_test_install_custom_mm_handler ();
623
+ } else {
624
+ zend_test_uninstall_custom_mm_handler ();
569
625
}
570
626
return OnUpdateBool (entry , new_value , mh_arg1 , mh_arg2 , mh_arg3 , stage );
571
627
}
@@ -970,11 +1026,7 @@ PHP_RSHUTDOWN_FUNCTION(zend_test)
970
1026
} ZEND_HASH_FOREACH_END ();
971
1027
zend_hash_destroy (& ZT_G (global_weakmap ));
972
1028
973
- if (ZT_G (zend_test_heap )) {
974
- free (ZT_G (zend_test_heap ));
975
- ZT_G (zend_test_heap ) = NULL ;
976
- zend_mm_set_heap (ZT_G (zend_orig_heap ));
977
- }
1029
+ zend_test_uninstall_custom_mm_handler ();
978
1030
979
1031
return SUCCESS ;
980
1032
}
0 commit comments