From af56c6ec798ca34d2dd9a85ecb7865f3e897342c Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 12 Nov 2024 18:07:41 +0100 Subject: [PATCH] Refresh zend_mm shadow key on fork --- Zend/zend_alloc.c | 53 +++++++++++++++++++++--------- Zend/zend_alloc.h | 1 + ext/pcntl/pcntl.c | 2 ++ main/main.c | 5 +++ main/php_main.h | 1 + sapi/apache2handler/sapi_apache2.c | 1 + sapi/cgi/cgi_main.c | 2 ++ sapi/cli/php_cli_server.c | 1 + sapi/fpm/fpm/fpm_php.c | 3 ++ 9 files changed, 54 insertions(+), 15 deletions(-) diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 2c8023e62577e..67dc8555ff30b 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -70,8 +70,6 @@ # include # include # include "win32/winutil.h" -# define getpid _getpid -typedef int pid_t; #endif #include @@ -307,7 +305,6 @@ struct _zend_mm_heap { } custom_heap; HashTable *tracked_allocs; #endif - pid_t pid; zend_random_bytes_insecure_state rand_state; }; @@ -1300,15 +1297,20 @@ static zend_always_inline zend_mm_free_slot* zend_mm_encode_free_slot(const zend #endif } -static zend_always_inline zend_mm_free_slot* zend_mm_decode_free_slot(zend_mm_heap *heap, zend_mm_free_slot *slot) +static zend_always_inline zend_mm_free_slot* zend_mm_decode_free_slot_key(uintptr_t shadow_key, zend_mm_free_slot *slot) { #ifdef WORDS_BIGENDIAN - return (zend_mm_free_slot*)((uintptr_t)slot ^ heap->shadow_key); + return (zend_mm_free_slot*)((uintptr_t)slot ^ shadow_key); #else - return (zend_mm_free_slot*)(BSWAPPTR((uintptr_t)slot ^ heap->shadow_key)); + return (zend_mm_free_slot*)(BSWAPPTR((uintptr_t)slot ^ shadow_key)); #endif } +static zend_always_inline zend_mm_free_slot* zend_mm_decode_free_slot(zend_mm_heap *heap, zend_mm_free_slot *slot) +{ + return zend_mm_decode_free_slot_key(heap->shadow_key, slot); +} + static zend_always_inline void zend_mm_set_next_free_slot(zend_mm_heap *heap, uint32_t bin_num, zend_mm_free_slot *slot, zend_mm_free_slot *next) { ZEND_ASSERT(bin_data_size[bin_num] >= ZEND_MM_MIN_USEABLE_BIN_SIZE); @@ -2017,6 +2019,30 @@ static void zend_mm_init_key(zend_mm_heap *heap) zend_mm_refresh_key(heap); } +static void zend_mm_refresh_key_child(zend_mm_heap *heap) +{ + uintptr_t old_key = heap->shadow_key; + + zend_mm_init_key(heap); + + /* Update shadow pointers with new key */ + for (int i = 0; i < ZEND_MM_BINS; i++) { + zend_mm_free_slot *slot = heap->free_slot[i]; + if (!slot) { + continue; + } + zend_mm_free_slot *next; + while ((next = slot->next_free_slot)) { + zend_mm_free_slot *shadow = ZEND_MM_FREE_SLOT_PTR_SHADOW(slot, i); + if (UNEXPECTED(next != zend_mm_decode_free_slot_key(old_key, shadow))) { + zend_mm_panic("zend_mm_heap corrupted"); + } + zend_mm_set_next_free_slot(heap, i, slot, next); + slot = next; + } + } +} + static zend_mm_heap *zend_mm_init(void) { zend_mm_chunk *chunk = (zend_mm_chunk*)zend_mm_chunk_alloc_int(ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE); @@ -2065,7 +2091,6 @@ static zend_mm_heap *zend_mm_init(void) heap->storage = NULL; #endif heap->huge_list = NULL; - heap->pid = getpid(); return heap; } @@ -2511,13 +2536,7 @@ ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent) p->free_map[0] = (1L << ZEND_MM_FIRST_PAGE) - 1; p->map[0] = ZEND_MM_LRUN(ZEND_MM_FIRST_PAGE); - pid_t pid = getpid(); - if (heap->pid != pid) { - zend_mm_init_key(heap); - heap->pid = pid; - } else { - zend_mm_refresh_key(heap); - } + zend_mm_refresh_key(heap); } } @@ -2924,6 +2943,11 @@ ZEND_API void shutdown_memory_manager(bool silent, bool full_shutdown) zend_mm_shutdown(AG(mm_heap), full_shutdown, silent); } +ZEND_API void refresh_memory_manager(void) +{ + zend_mm_refresh_key_child(AG(mm_heap)); +} + static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) { fprintf(stderr, "Out of memory\n"); @@ -3268,7 +3292,6 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void memcpy(storage->data, data, data_size); } heap->storage = storage; - heap->pid = getpid(); return heap; #else return NULL; diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h index 541989a2a13e0..d45ff01a9bf4f 100644 --- a/Zend/zend_alloc.h +++ b/Zend/zend_alloc.h @@ -220,6 +220,7 @@ ZEND_API bool zend_alloc_in_memory_limit_error_reporting(void); ZEND_API void start_memory_manager(void); ZEND_API void shutdown_memory_manager(bool silent, bool full_shutdown); +ZEND_API void refresh_memory_manager(void); ZEND_API bool is_zend_mm(void); ZEND_API bool is_zend_ptr(const void *ptr); diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index b2fe964e7face..9d5e385de561d 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -32,6 +32,7 @@ #include "php_signal.h" #include "php_ticks.h" #include "zend_fibers.h" +#include "main/php_main.h" #if defined(HAVE_GETPRIORITY) || defined(HAVE_SETPRIORITY) || defined(HAVE_WAIT3) #include @@ -292,6 +293,7 @@ PHP_FUNCTION(pcntl_fork) } } else if (id == 0) { + php_child_init(); zend_max_execution_timer_init(); } diff --git a/main/main.c b/main/main.c index 0b38f303c58fc..c4efa91a5ec28 100644 --- a/main/main.c +++ b/main/main.c @@ -1797,6 +1797,11 @@ static void sigchld_handler(int apar) /* }}} */ #endif +PHPAPI void php_child_init(void) +{ + refresh_memory_manager(); +} + /* {{{ php_request_startup */ zend_result php_request_startup(void) { diff --git a/main/php_main.h b/main/php_main.h index 889fcf48501f0..f361226adde20 100644 --- a/main/php_main.h +++ b/main/php_main.h @@ -42,6 +42,7 @@ PHPAPI unsigned int php_version_id(void); PHPAPI char *php_get_version(sapi_module_struct *sapi_module); PHPAPI void php_print_version(sapi_module_struct *sapi_module); +PHPAPI void php_child_init(void); PHPAPI zend_result php_request_startup(void); PHPAPI void php_request_shutdown(void *dummy); PHPAPI zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_module); diff --git a/sapi/apache2handler/sapi_apache2.c b/sapi/apache2handler/sapi_apache2.c index 1d85a92ebf4d8..ca93d86515ad1 100644 --- a/sapi/apache2handler/sapi_apache2.c +++ b/sapi/apache2handler/sapi_apache2.c @@ -751,6 +751,7 @@ zend_first_try { static void php_apache_child_init(apr_pool_t *pchild, server_rec *s) { apr_pool_cleanup_register(pchild, NULL, php_apache_child_shutdown, apr_pool_cleanup_null); + php_child_init(); } #ifdef ZEND_SIGNALS diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 0e7b3009c6024..5815d88de8c8e 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -2043,6 +2043,8 @@ consult the installation file that came with this distribution, or visit \n\ */ parent = 0; + php_child_init(); + /* don't catch our signals */ sigaction(SIGTERM, &old_term, 0); sigaction(SIGQUIT, &old_quit, 0); diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index bcf5af320d73b..e99e618cb7b2a 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -2528,6 +2528,7 @@ static void php_cli_server_startup_workers(void) { #if defined(HAVE_PRCTL) || defined(HAVE_PROCCTL) php_cli_server_worker_install_pdeathsig(); #endif + php_child_init(); return; } else { php_cli_server_workers[php_cli_server_worker] = pid; diff --git a/sapi/fpm/fpm/fpm_php.c b/sapi/fpm/fpm/fpm_php.c index d93459b4ea370..93884d7683bcd 100644 --- a/sapi/fpm/fpm/fpm_php.c +++ b/sapi/fpm/fpm/fpm_php.c @@ -239,6 +239,9 @@ int fpm_php_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ limit_extensions = wp->limit_extensions; wp->limit_extensions = NULL; } + + php_child_init(); + return 0; } /* }}} */