@@ -517,28 +517,110 @@ 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
+ void * (* custom_malloc )(size_t );
603
+ void (* custom_free )(void * );
604
+ void * (* custom_realloc )(void * , size_t );
605
+ zend_mm_get_custom_handlers (
606
+ zend_mm_get_heap (),
607
+ & custom_malloc ,
608
+ & custom_free ,
609
+ & custom_realloc
610
+ );
611
+ if (custom_malloc == zend_test_custom_malloc ||
612
+ custom_free == zend_test_custom_free ||
613
+ custom_realloc == zend_test_custom_realloc ) {
614
+ zend_mm_set_custom_handlers (
615
+ zend_mm_get_heap (),
616
+ ZT_G (zendmm_orig_malloc ),
617
+ ZT_G (zendmm_orig_free ),
618
+ ZT_G (zendmm_orig_realloc )
619
+ );
620
+ ZT_G (zendmm_orig_malloc ) = NULL ;
621
+ ZT_G (zendmm_orig_free ) = NULL ;
622
+ ZT_G (zendmm_orig_realloc ) = NULL ;
623
+ }
542
624
}
543
625
544
626
static PHP_INI_MH (OnUpdateZendTestObserveOplineInZendMM )
@@ -550,22 +632,9 @@ static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)
550
632
int int_value = zend_ini_parse_bool (new_value );
551
633
552
634
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 ));
635
+ zend_test_install_custom_mm_handler ();
636
+ } else {
637
+ zend_test_uninstall_custom_mm_handler ();
569
638
}
570
639
return OnUpdateBool (entry , new_value , mh_arg1 , mh_arg2 , mh_arg3 , stage );
571
640
}
@@ -948,6 +1017,8 @@ PHP_MSHUTDOWN_FUNCTION(zend_test)
948
1017
949
1018
zend_test_observer_shutdown (SHUTDOWN_FUNC_ARGS_PASSTHRU );
950
1019
1020
+ zend_test_uninstall_custom_mm_handler ();
1021
+
951
1022
if (ZT_G (print_stderr_mshutdown )) {
952
1023
fprintf (stderr , "[zend-test] MSHUTDOWN\n" );
953
1024
}
@@ -970,12 +1041,6 @@ PHP_RSHUTDOWN_FUNCTION(zend_test)
970
1041
} ZEND_HASH_FOREACH_END ();
971
1042
zend_hash_destroy (& ZT_G (global_weakmap ));
972
1043
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
- }
978
-
979
1044
return SUCCESS ;
980
1045
}
981
1046
0 commit comments