Skip to content

Commit f4557b4

Browse files
Add gc and shutdown callbacks to ZendMM custom handlers (#13432)
1 parent a1ea464 commit f4557b4

11 files changed

+340
-16
lines changed

Zend/zend_alloc.c

+61-8
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ struct _zend_mm_heap {
334334
void *(*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
335335
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
336336
void *(*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
337+
size_t (*_gc)(void);
338+
void (*_shutdown)(bool full, bool silent);
337339
} custom_heap;
338340
HashTable *tracked_allocs;
339341
#endif
@@ -2119,6 +2121,10 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
21192121

21202122
#if ZEND_MM_CUSTOM
21212123
if (heap->use_custom_heap) {
2124+
size_t (*gc)(void) = heap->custom_heap._gc;
2125+
if (gc) {
2126+
return gc();
2127+
}
21222128
return 0;
21232129
}
21242130
#endif
@@ -2421,10 +2427,10 @@ static void zend_mm_check_leaks(zend_mm_heap *heap)
24212427

24222428
#if ZEND_MM_CUSTOM
24232429
static void *tracked_malloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
2424-
static void tracked_free_all(void);
2430+
static void tracked_free_all(zend_mm_heap *heap);
24252431
#endif
24262432

2427-
void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
2433+
ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
24282434
{
24292435
zend_mm_chunk *p;
24302436
zend_mm_huge_list *list;
@@ -2433,7 +2439,7 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
24332439
if (heap->use_custom_heap) {
24342440
if (heap->custom_heap._malloc == tracked_malloc) {
24352441
if (silent) {
2436-
tracked_free_all();
2442+
tracked_free_all(heap);
24372443
}
24382444
zend_hash_clean(heap->tracked_allocs);
24392445
if (full) {
@@ -2445,9 +2451,16 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
24452451
heap->size = 0;
24462452
}
24472453

2454+
void (*shutdown)(bool, bool) = heap->custom_heap._shutdown;
2455+
24482456
if (full) {
24492457
heap->custom_heap._free(heap ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
24502458
}
2459+
2460+
if (shutdown) {
2461+
shutdown(full, silent);
2462+
}
2463+
24512464
return;
24522465
}
24532466
#endif
@@ -3039,8 +3052,8 @@ static void *tracked_realloc(void *ptr, size_t new_size ZEND_FILE_LINE_DC ZEND_F
30393052
return ptr;
30403053
}
30413054

3042-
static void tracked_free_all(void) {
3043-
HashTable *tracked_allocs = AG(mm_heap)->tracked_allocs;
3055+
static void tracked_free_all(zend_mm_heap *heap) {
3056+
HashTable *tracked_allocs = heap->tracked_allocs;
30443057
zend_ulong h;
30453058
ZEND_HASH_FOREACH_NUM_KEY(tracked_allocs, h) {
30463059
void *ptr = (void *) (uintptr_t) (h << ZEND_MM_ALIGNMENT_LOG2);
@@ -3138,6 +3151,18 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
31383151
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
31393152
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC))
31403153
{
3154+
#if ZEND_MM_CUSTOM
3155+
zend_mm_set_custom_handlers_ex(heap, _malloc, _free, _realloc, NULL, NULL);
3156+
#endif
3157+
}
3158+
3159+
ZEND_API void zend_mm_set_custom_handlers_ex(zend_mm_heap *heap,
3160+
void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3161+
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3162+
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3163+
size_t (*_gc)(void),
3164+
void (*_shutdown)(bool, bool))
3165+
{
31413166
#if ZEND_MM_CUSTOM
31423167
zend_mm_heap *_heap = (zend_mm_heap*)heap;
31433168

@@ -3148,14 +3173,28 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
31483173
_heap->custom_heap._malloc = _malloc;
31493174
_heap->custom_heap._free = _free;
31503175
_heap->custom_heap._realloc = _realloc;
3176+
_heap->custom_heap._gc = _gc;
3177+
_heap->custom_heap._shutdown = _shutdown;
31513178
}
31523179
#endif
31533180
}
31543181

31553182
ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
3156-
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3157-
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3158-
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC))
3183+
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3184+
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3185+
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC))
3186+
{
3187+
#if ZEND_MM_CUSTOM
3188+
zend_mm_get_custom_handlers_ex(heap, _malloc, _free, _realloc, NULL, NULL);
3189+
#endif
3190+
}
3191+
3192+
ZEND_API void zend_mm_get_custom_handlers_ex(zend_mm_heap *heap,
3193+
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3194+
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3195+
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3196+
size_t (**_gc)(void),
3197+
void (**_shutdown)(bool, bool))
31593198
{
31603199
#if ZEND_MM_CUSTOM
31613200
zend_mm_heap *_heap = (zend_mm_heap*)heap;
@@ -3164,15 +3203,29 @@ ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
31643203
*_malloc = _heap->custom_heap._malloc;
31653204
*_free = _heap->custom_heap._free;
31663205
*_realloc = _heap->custom_heap._realloc;
3206+
if (_gc != NULL) {
3207+
*_gc = _heap->custom_heap._gc;
3208+
}
3209+
if (_shutdown != NULL) {
3210+
*_shutdown = _heap->custom_heap._shutdown;
3211+
}
31673212
} else {
31683213
*_malloc = NULL;
31693214
*_free = NULL;
31703215
*_realloc = NULL;
3216+
if (_gc != NULL) {
3217+
*_gc = NULL;
3218+
}
3219+
if (_shutdown != NULL) {
3220+
*_shutdown = NULL;
3221+
}
31713222
}
31723223
#else
31733224
*_malloc = NULL;
31743225
*_free = NULL;
31753226
*_realloc = NULL;
3227+
*_gc = NULL;
3228+
*_shutdown = NULL;
31763229
#endif
31773230
}
31783231

Zend/zend_alloc.h

+18-6
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,25 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap);
274274

275275
ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap);
276276
ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
277-
void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
278-
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
279-
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC));
277+
void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
278+
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
279+
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC));
280+
ZEND_API void zend_mm_set_custom_handlers_ex(zend_mm_heap *heap,
281+
void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
282+
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
283+
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
284+
size_t (*_gc)(void),
285+
void (*_shutdown)(bool, bool));
280286
ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
281-
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
282-
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
283-
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC));
287+
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
288+
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
289+
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC));
290+
ZEND_API void zend_mm_get_custom_handlers_ex(zend_mm_heap *heap,
291+
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
292+
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
293+
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
294+
size_t (**_gc)(void),
295+
void (**_shutdown)(bool, bool));
284296

285297
typedef struct _zend_mm_storage zend_mm_storage;
286298

ext/zend_test/config.m4

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ PHP_ARG_ENABLE([zend-test],
44
[Enable zend_test extension])])
55

66
if test "$PHP_ZEND_TEST" != "no"; then
7-
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c iterators.c object_handlers.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
7+
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c iterators.c object_handlers.c zend_mm_custom_handlers.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
88
fi

ext/zend_test/config.w32

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
ARG_ENABLE("zend-test", "enable zend_test extension", "no");
44

55
if (PHP_ZEND_TEST != "no") {
6-
EXTENSION("zend_test", "test.c observer.c fiber.c iterators.c object_handlers.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
6+
EXTENSION("zend_test", "test.c observer.c fiber.c iterators.c object_handlers.c zend_mm_custom_handlers.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
77
ADD_FLAG("CFLAGS_ZEND_TEST", "/D PHP_ZEND_TEST_EXPORTS ");
88
}

ext/zend_test/php_test.h

+13
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
6262
zend_long quantity_value;
6363
zend_string *str_test;
6464
zend_string *not_empty_str_test;
65+
int zend_mm_custom_handlers_enabled;
66+
67+
// the previous heap that was found in ZendMM
68+
zend_mm_heap* original_heap;
69+
// the custom handlers that might have been found in the previous heap
70+
void* (*custom_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
71+
void (*custom_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
72+
void* (*custom_realloc)(void *, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
73+
size_t (*custom_gc)(void);
74+
void (*custom_shutdown)(bool, bool);
75+
// this is our heap that we install our custom handlers on and inject into
76+
// ZendMM
77+
zend_mm_heap* observed_heap;
6578
ZEND_END_MODULE_GLOBALS(zend_test)
6679

6780
extern ZEND_DECLARE_MODULE_GLOBALS(zend_test)

ext/zend_test/test.c

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
+----------------------------------------------------------------------+
1515
*/
1616

17+
#include "zend_modules.h"
1718
#ifdef HAVE_CONFIG_H
1819
# include "config.h"
1920
#endif
@@ -35,6 +36,7 @@
3536
#include "test_arginfo.h"
3637
#include "zend_call_stack.h"
3738
#include "zend_exceptions.h"
39+
#include "zend_mm_custom_handlers.h"
3840

3941
// `php.h` sets `NDEBUG` when not `PHP_DEBUG` which will make `assert()` from
4042
// assert.h a no-op. In order to have `assert()` working on NDEBUG builds, we
@@ -1282,6 +1284,7 @@ PHP_MINIT_FUNCTION(zend_test)
12821284
}
12831285

12841286
zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
1287+
zend_test_mm_custom_handlers_minit(INIT_FUNC_ARGS_PASSTHRU);
12851288
zend_test_fiber_init();
12861289
zend_test_iterators_init();
12871290
zend_test_object_handlers_init();
@@ -1310,6 +1313,7 @@ PHP_RINIT_FUNCTION(zend_test)
13101313
{
13111314
zend_hash_init(&ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0);
13121315
ZT_G(observer_nesting_depth) = 0;
1316+
zend_test_mm_custom_handlers_rinit();
13131317
return SUCCESS;
13141318
}
13151319

@@ -1327,6 +1331,7 @@ PHP_RSHUTDOWN_FUNCTION(zend_test)
13271331
zend_mm_set_heap(ZT_G(zend_orig_heap));
13281332
}
13291333

1334+
zend_test_mm_custom_handlers_rshutdown();
13301335
return SUCCESS;
13311336
}
13321337

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
ZendMM Custom Handlers: garbage collection
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 1);
8+
$string = str_repeat('String', rand(1,100));
9+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 0);
10+
?>
11+
--EXPECTREGEX--
12+
.*Allocated \d+ bytes at.*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
ZendMM Custom Handlers: garbage collection
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
$string = str_repeat('String', rand(1,100));
8+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 1);
9+
unset($string);
10+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 0);
11+
?>
12+
--EXPECTREGEX--
13+
.*Freed memory at.*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
ZendMM Custom Handlers: garbage collection
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 1);
8+
gc_mem_caches();
9+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 0);
10+
?>
11+
--EXPECTREGEX--
12+
.*ZendMM GC freed \d+ bytes.*

0 commit comments

Comments
 (0)