Skip to content

Commit 6d67096

Browse files
support neighbouring extension in the ZendMM custom handlers hook
1 parent ebb4488 commit 6d67096

File tree

4 files changed

+95
-31
lines changed

4 files changed

+95
-31
lines changed

ext/zend_test/php_test.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,11 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
5656
bool print_stderr_mshutdown;
5757
zend_long limit_copy_file_range;
5858
int observe_opline_in_zendmm;
59-
zend_mm_heap* zend_orig_heap;
60-
zend_mm_heap* zend_test_heap;
59+
// previous handlers that might have been installed
60+
// `USE_ZEND_ALLOC=0` installs custom handlers
61+
void* (*zendmm_orig_malloc)(size_t);
62+
void (*zendmm_orig_free)(void*);
63+
void* (*zendmm_orig_realloc)(void *, size_t);
6164
zend_test_fiber *active_fiber;
6265
zend_long quantity_value;
6366
zend_string *str_test;

ext/zend_test/test.c

Lines changed: 90 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -517,28 +517,110 @@ static bool has_opline(zend_execute_data *execute_data)
517517
;
518518
}
519519

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+
520539
void * zend_test_custom_malloc(size_t len)
521540
{
522541
if (has_opline(EG(current_execute_data))) {
523542
assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
524543
}
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;
526551
}
527552

528553
void zend_test_custom_free(void *ptr)
529554
{
530555
if (has_opline(EG(current_execute_data))) {
531556
assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
532557
}
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);
534565
}
535566

536567
void * zend_test_custom_realloc(void * ptr, size_t len)
537568
{
538569
if (has_opline(EG(current_execute_data))) {
539570
assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
540571
}
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+
}
542624
}
543625

544626
static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)
@@ -550,22 +632,9 @@ static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)
550632
int int_value = zend_ini_parse_bool(new_value);
551633

552634
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();
569638
}
570639
return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
571640
}
@@ -948,6 +1017,8 @@ PHP_MSHUTDOWN_FUNCTION(zend_test)
9481017

9491018
zend_test_observer_shutdown(SHUTDOWN_FUNC_ARGS_PASSTHRU);
9501019

1020+
zend_test_uninstall_custom_mm_handler();
1021+
9511022
if (ZT_G(print_stderr_mshutdown)) {
9521023
fprintf(stderr, "[zend-test] MSHUTDOWN\n");
9531024
}
@@ -970,12 +1041,6 @@ PHP_RSHUTDOWN_FUNCTION(zend_test)
9701041
} ZEND_HASH_FOREACH_END();
9711042
zend_hash_destroy(&ZT_G(global_weakmap));
9721043

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-
9791044
return SUCCESS;
9801045
}
9811046

ext/zend_test/tests/opline_dangling.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ possible segfault in `ZEND_BIND_STATIC`
44
https://github.com/php/php-src/pull/12758
55
--EXTENSIONS--
66
zend_test
7-
--ENV--
8-
USE_ZEND_ALLOC=1
97
--INI--
108
zend_test.observe_opline_in_zendmm=1
119
--FILE--

ext/zend_test/tests/opline_dangling_02.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
possible segfault in `ZEND_FUNC_GET_ARGS`
33
--EXTENSIONS--
44
zend_test
5-
--ENV--
6-
USE_ZEND_ALLOC=1
75
--INI--
86
zend_test.observe_opline_in_zendmm=1
97
--FILE--

0 commit comments

Comments
 (0)