Skip to content

Commit cfeda97

Browse files
committed
Add tracked allocator mode
In this case we will use the system allocator, but still remember all allocations and free them the same way that Zend MM does. This allows us to accurately model leak behavior. Enabled using USE_ZEND_ALLOC=0 USE_TRACKED_ALLOC=1.
1 parent 218c185 commit cfeda97

File tree

1 file changed

+71
-11
lines changed

1 file changed

+71
-11
lines changed

Zend/zend_alloc.c

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ struct _zend_mm_heap {
266266
void *(*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
267267
} debug;
268268
} custom_heap;
269+
HashTable *tracked_allocs;
269270
#endif
270271
};
271272

@@ -2182,20 +2183,32 @@ static void zend_mm_check_leaks(zend_mm_heap *heap)
21822183
}
21832184
#endif
21842185

2186+
#if ZEND_MM_CUSTOM
2187+
static void *tracked_malloc(size_t size);
2188+
static void tracked_free_all();
2189+
#endif
2190+
21852191
void zend_mm_shutdown(zend_mm_heap *heap, int full, int silent)
21862192
{
21872193
zend_mm_chunk *p;
21882194
zend_mm_huge_list *list;
21892195

21902196
#if ZEND_MM_CUSTOM
21912197
if (heap->use_custom_heap) {
2192-
if (full) {
2193-
if (ZEND_DEBUG && heap->use_custom_heap == ZEND_MM_CUSTOM_HEAP_DEBUG) {
2194-
heap->custom_heap.debug._free(heap ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
2195-
} else {
2196-
heap->custom_heap.std._free(heap);
2198+
if (heap->custom_heap.std._malloc == tracked_malloc) {
2199+
if (silent) {
2200+
tracked_free_all();
2201+
}
2202+
zend_hash_clean(heap->tracked_allocs);
2203+
if (full) {
2204+
zend_hash_destroy(heap->tracked_allocs);
2205+
free(heap->tracked_allocs);
21972206
}
21982207
}
2208+
2209+
if (full) {
2210+
free(heap);
2211+
}
21992212
return;
22002213
}
22012214
#endif
@@ -2661,19 +2674,66 @@ ZEND_API void shutdown_memory_manager(int silent, int full_shutdown)
26612674
zend_mm_shutdown(AG(mm_heap), full_shutdown, silent);
26622675
}
26632676

2677+
#if ZEND_MM_CUSTOM
2678+
static void *tracked_malloc(size_t size)
2679+
{
2680+
void *ptr = __zend_malloc(size);
2681+
zend_ulong h = ((uintptr_t) ptr) >> ZEND_MM_ALIGNMENT_LOG2;
2682+
ZEND_ASSERT((void *) (uintptr_t) (h << ZEND_MM_ALIGNMENT_LOG2) == ptr);
2683+
zend_hash_index_add_empty_element(AG(mm_heap)->tracked_allocs, h);
2684+
return ptr;
2685+
}
2686+
2687+
static void tracked_free(void *ptr) {
2688+
zend_ulong h = ((uintptr_t) ptr) >> ZEND_MM_ALIGNMENT_LOG2;
2689+
zend_hash_index_del(AG(mm_heap)->tracked_allocs, h);
2690+
free(ptr);
2691+
}
2692+
2693+
static void *tracked_realloc(void *ptr, size_t new_size) {
2694+
zend_ulong h = ((uintptr_t) ptr) >> ZEND_MM_ALIGNMENT_LOG2;
2695+
zend_hash_index_del(AG(mm_heap)->tracked_allocs, h);
2696+
ptr = __zend_realloc(ptr, new_size);
2697+
h = ((uintptr_t) ptr) >> ZEND_MM_ALIGNMENT_LOG2;
2698+
ZEND_ASSERT((void *) (uintptr_t) (h << ZEND_MM_ALIGNMENT_LOG2) == ptr);
2699+
zend_hash_index_add_empty_element(AG(mm_heap)->tracked_allocs, h);
2700+
return ptr;
2701+
}
2702+
2703+
static void tracked_free_all() {
2704+
HashTable *tracked_allocs = AG(mm_heap)->tracked_allocs;
2705+
zend_ulong h;
2706+
ZEND_HASH_FOREACH_NUM_KEY(tracked_allocs, h) {
2707+
void *ptr = (void *) (uintptr_t) (h << ZEND_MM_ALIGNMENT_LOG2);
2708+
free(ptr);
2709+
} ZEND_HASH_FOREACH_END();
2710+
}
2711+
#endif
2712+
26642713
static void alloc_globals_ctor(zend_alloc_globals *alloc_globals)
26652714
{
26662715
char *tmp;
26672716

26682717
#if ZEND_MM_CUSTOM
26692718
tmp = getenv("USE_ZEND_ALLOC");
26702719
if (tmp && !zend_atoi(tmp, 0)) {
2671-
alloc_globals->mm_heap = malloc(sizeof(zend_mm_heap));
2672-
memset(alloc_globals->mm_heap, 0, sizeof(zend_mm_heap));
2673-
alloc_globals->mm_heap->use_custom_heap = ZEND_MM_CUSTOM_HEAP_STD;
2674-
alloc_globals->mm_heap->custom_heap.std._malloc = __zend_malloc;
2675-
alloc_globals->mm_heap->custom_heap.std._free = free;
2676-
alloc_globals->mm_heap->custom_heap.std._realloc = __zend_realloc;
2720+
zend_bool tracked = (tmp = getenv("USE_TRACKED_ALLOC")) && zend_atoi(tmp, 0);
2721+
zend_mm_heap *mm_heap = alloc_globals->mm_heap = malloc(sizeof(zend_mm_heap));
2722+
memset(mm_heap, 0, sizeof(zend_mm_heap));
2723+
mm_heap->use_custom_heap = ZEND_MM_CUSTOM_HEAP_STD;
2724+
if (!tracked) {
2725+
/* Use system allocator. */
2726+
mm_heap->custom_heap.std._malloc = __zend_malloc;
2727+
mm_heap->custom_heap.std._free = free;
2728+
mm_heap->custom_heap.std._realloc = __zend_realloc;
2729+
} else {
2730+
/* Use system allocator and track allocations for auto-free. */
2731+
mm_heap->custom_heap.std._malloc = tracked_malloc;
2732+
mm_heap->custom_heap.std._free = tracked_free;
2733+
mm_heap->custom_heap.std._realloc = tracked_realloc;
2734+
mm_heap->tracked_allocs = malloc(sizeof(HashTable));
2735+
zend_hash_init(mm_heap->tracked_allocs, 1024, NULL, NULL, 1);
2736+
}
26772737
return;
26782738
}
26792739
#endif

0 commit comments

Comments
 (0)