Commit 49f8de7ae5b for php
commit 49f8de7ae5bf7be9119e81bd081c823a1cc8580b
Author: Marc Bennewitz <marc-mabe@users.noreply.github.com>
Date: Mon Sep 28 19:51:21 2026 +0200
zend_alloc: use uint32_t for small bin numbers (#23960)
zend_mm_alloc_small() and zend_mm_free_small() took the bin number as a
signed int, while zend_mm_alloc_small_slow() and the other bin helpers
take uint32_t. The bin number indexes bin_data_size[] several times per
call, and with the signed type GCC failed to see that the indexes are the
same, so it loaded bin_data_size[bin_num] twice on the emalloc() and
efree() fast paths and more often in zend_mm_realloc_heap().
Take the bin number as uint32_t in both, return it as such from
zend_mm_small_size_to_bin(), and declare old_bin_num in
zend_mm_realloc_heap() accordingly.
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c
index 4fc8926c0fc..c652cbd39ce 100644
--- a/Zend/zend_alloc.c
+++ b/Zend/zend_alloc.c
@@ -1269,7 +1269,7 @@ static zend_always_inline void zend_mm_free_large(zend_mm_heap *heap, zend_mm_ch
/**************/
/* higher set bit number (0->N/A, 1->1, 2->2, 4->3, 8->4, 127->7, 128->8 etc) */
-static zend_always_inline int zend_mm_small_size_to_bit(int size)
+static zend_always_inline int zend_mm_small_size_to_bit(uint32_t size)
{
#if (defined(__GNUC__) || __has_builtin(__builtin_clz)) && defined(PHP_HAVE_BUILTIN_CLZ)
return (__builtin_clz(size) ^ 0x1f) + 1;
@@ -1300,19 +1300,19 @@ static zend_always_inline int zend_mm_small_size_to_bit(int size)
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
-static zend_always_inline int zend_mm_small_size_to_bin(size_t size)
+static zend_always_inline uint32_t zend_mm_small_size_to_bin(size_t size)
{
#if 0
int n;
- /*0, 1, 2, 3, 4, 5, 6, 7, 8, 9 10, 11, 12*/
- static const int f1[] = { 3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9};
- static const int f2[] = { 0, 0, 0, 0, 0, 0, 0, 4, 8, 12, 16, 20, 24};
+ /*0, 1, 2, 3, 4, 5, 6, 7, 8, 9 10, 11, 12*/
+ static const uint32_t f1[] = { 3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9};
+ static const uint32_t f2[] = { 0, 0, 0, 0, 0, 0, 0, 4, 8, 12, 16, 20, 24};
if (UNEXPECTED(size <= 2)) return 0;
n = zend_mm_small_size_to_bit(size - 1);
return ((size-1) >> f1[n]) + f2[n];
#else
- unsigned int t1, t2;
+ uint32_t t1, t2;
if (size <= 64) {
/* we need to support size == 0 ... */
@@ -1323,7 +1323,7 @@ static zend_always_inline int zend_mm_small_size_to_bin(size_t size)
t1 = t1 >> t2;
t2 = t2 - 3;
t2 = t2 << 2;
- return (int)(t1 + t2);
+ return t1 + t2;
}
#endif
}
@@ -1457,7 +1457,7 @@ static zend_never_inline void *zend_mm_alloc_small_slow(zend_mm_heap *heap, uint
return bin;
}
-static zend_always_inline void *zend_mm_alloc_small(zend_mm_heap *heap, int bin_num ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
+static zend_always_inline void *zend_mm_alloc_small(zend_mm_heap *heap, uint32_t bin_num ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
ZEND_ASSERT(bin_data_size[bin_num] >= ZEND_MM_MIN_USEABLE_BIN_SIZE);
@@ -1479,7 +1479,7 @@ static zend_always_inline void *zend_mm_alloc_small(zend_mm_heap *heap, int bin_
}
}
-static zend_always_inline void zend_mm_free_small(zend_mm_heap *heap, void *ptr, int bin_num)
+static zend_always_inline void zend_mm_free_small(zend_mm_heap *heap, void *ptr, uint32_t bin_num)
{
ZEND_ASSERT(bin_data_size[bin_num] >= ZEND_MM_MIN_USEABLE_BIN_SIZE);
@@ -1525,7 +1525,7 @@ static zend_always_inline zend_mm_debug_info *zend_mm_get_debug_info(zend_mm_hea
info = chunk->map[page_num];
ZEND_MM_CHECK(chunk->heap == heap, "zend_mm_heap corrupted");
if (EXPECTED(info & ZEND_MM_IS_SRUN)) {
- int bin_num = ZEND_MM_SRUN_BIN_NUM(info);
+ uint32_t bin_num = ZEND_MM_SRUN_BIN_NUM(info);
return (zend_mm_debug_info*)((char*)ptr + bin_data_size[bin_num] - ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)));
} else /* if (info & ZEND_MM_IS_LRUN) */ {
int pages_count = ZEND_MM_LRUN_PAGES(info);
@@ -1779,7 +1779,7 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p
ZEND_MM_CHECK(chunk->heap == heap, "zend_mm_heap corrupted");
if (info & ZEND_MM_IS_SRUN) {
- int old_bin_num = ZEND_MM_SRUN_BIN_NUM(info);
+ uint32_t old_bin_num = ZEND_MM_SRUN_BIN_NUM(info);
do {
old_size = bin_data_size[old_bin_num];
@@ -2124,7 +2124,7 @@ ZEND_API void zend_mm_refresh_key_child(zend_mm_heap *heap)
zend_mm_init_key(heap);
/* Update shadow pointers with new key */
- for (int i = 0; i < ZEND_MM_BINS; i++) {
+ for (uint32_t i = 0; i < ZEND_MM_BINS; i++) {
zend_mm_free_slot *slot = heap->free_slot[i];
if (!slot) {
continue;
@@ -2299,7 +2299,7 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
if (zend_mm_bitset_is_set(chunk->free_map, i)) {
info = chunk->map[i];
if (info & ZEND_MM_IS_SRUN) {
- int bin_num = ZEND_MM_SRUN_BIN_NUM(info);
+ uint32_t bin_num = ZEND_MM_SRUN_BIN_NUM(info);
int pages_count = bin_pages[bin_num];
if (ZEND_MM_SRUN_FREE_COUNTER(info) == bin_elements[bin_num]) {
@@ -2340,7 +2340,7 @@ static zend_long zend_mm_find_leaks_small(zend_mm_chunk *p, uint32_t i, uint32_t
{
bool empty = true;
zend_long count = 0;
- int bin_num = ZEND_MM_SRUN_BIN_NUM(p->map[i]);
+ uint32_t bin_num = ZEND_MM_SRUN_BIN_NUM(p->map[i]);
zend_mm_debug_info *dbg = (zend_mm_debug_info*)((char*)p + ZEND_MM_PAGE_SIZE * i + bin_data_size[bin_num] * (j + 1) - ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)));
while (j < bin_elements[bin_num]) {
@@ -2371,7 +2371,7 @@ static zend_long zend_mm_find_leaks(zend_mm_heap *heap, zend_mm_chunk *p, uint32
while (i < p->free_tail) {
if (zend_mm_bitset_is_set(p->free_map, i)) {
if (p->map[i] & ZEND_MM_IS_SRUN) {
- int bin_num = ZEND_MM_SRUN_BIN_NUM(p->map[i]);
+ uint32_t bin_num = ZEND_MM_SRUN_BIN_NUM(p->map[i]);
count += zend_mm_find_leaks_small(p, i, 0, leak);
i += bin_pages[bin_num];
} else /* if (p->map[i] & ZEND_MM_IS_LRUN) */ {
@@ -2462,7 +2462,7 @@ static void zend_mm_check_leaks(zend_mm_heap *heap)
while (i < p->free_tail) {
if (zend_mm_bitset_is_set(p->free_map, i)) {
if (p->map[i] & ZEND_MM_IS_SRUN) {
- int bin_num = ZEND_MM_SRUN_BIN_NUM(p->map[i]);
+ uint32_t bin_num = ZEND_MM_SRUN_BIN_NUM(p->map[i]);
zend_mm_debug_info *dbg = (zend_mm_debug_info*)((char*)p + ZEND_MM_PAGE_SIZE * i + bin_data_size[bin_num] - ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info)));
j = 0;