Commit e228395787a for php.net

commit e228395787a13f2f9f5b474d6484c85e7ffa03c7
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date:   Fri Apr 3 11:27:52 2026 -0400

    Use pemalloc/perealloc for persistent allocations

    Replace direct malloc/realloc calls with OOM-safe pemalloc/perealloc
    (persistent: true) counterparts.

    Fixes GH-19200
    Fixes GH-17013
    Closes GH-21625

diff --git a/Zend/zend.c b/Zend/zend.c
index f4236053af3..f83389a96a6 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -1303,7 +1303,7 @@ ZEND_API void zend_append_version_info(const zend_extension *extension) /* {{{ *

 	snprintf(new_info, new_info_length, "    with %s v%s, %s, by %s\n", extension->name, extension->version, extension->copyright, extension->author);

-	zend_version_info = (char *) realloc(zend_version_info, zend_version_info_length+new_info_length + 1);
+	zend_version_info = (char *) perealloc(zend_version_info, zend_version_info_length+new_info_length + 1, true);
 	strncat(zend_version_info, new_info, new_info_length);
 	zend_version_info_length += new_info_length;
 	free(new_info);
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index c04217983b5..ccb770a9963 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -2504,19 +2504,19 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
 			dl_loaded_count++;
 		}
 	} ZEND_HASH_FOREACH_END();
-	module_request_startup_handlers = (zend_module_entry**)realloc(
+	module_request_startup_handlers = (zend_module_entry**)perealloc(
 		module_request_startup_handlers,
 	    sizeof(zend_module_entry*) *
 		(startup_count + 1 +
 		 shutdown_count + 1 +
-		 post_deactivate_count + 1));
+		 post_deactivate_count + 1), true);
 	module_request_startup_handlers[startup_count] = NULL;
 	module_request_shutdown_handlers = module_request_startup_handlers + startup_count + 1;
 	module_request_shutdown_handlers[shutdown_count] = NULL;
 	module_post_deactivate_handlers = module_request_shutdown_handlers + shutdown_count + 1;
 	module_post_deactivate_handlers[post_deactivate_count] = NULL;
 	/* Cannot reuse module_request_startup_handlers because it is freed in zend_destroy_modules, which happens before zend_unload_modules. */
-	modules_dl_loaded = realloc(modules_dl_loaded, sizeof(zend_module_entry*) * (dl_loaded_count + 1));
+	modules_dl_loaded = perealloc(modules_dl_loaded, sizeof(zend_module_entry*) * (dl_loaded_count + 1), true);
 	modules_dl_loaded[dl_loaded_count] = NULL;
 	startup_count = 0;

@@ -2543,10 +2543,10 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
 		}
 	} ZEND_HASH_FOREACH_END();

-	class_cleanup_handlers = (zend_class_entry**)realloc(
+	class_cleanup_handlers = (zend_class_entry**)perealloc(
 		class_cleanup_handlers,
 		sizeof(zend_class_entry*) *
-		(class_count + 1));
+		(class_count + 1), true);
 	class_cleanup_handlers[class_count] = NULL;

 	if (class_count) {
@@ -3143,7 +3143,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
 		}
 		lowercase_name = zend_string_tolower_ex(internal_function->function_name, type == MODULE_PERSISTENT);
 		lowercase_name = zend_new_interned_string(lowercase_name);
-		reg_function = malloc(sizeof(zend_internal_function));
+		reg_function = pemalloc(sizeof(zend_internal_function), true);
 		memcpy(reg_function, &function, sizeof(zend_internal_function));
 		if (zend_hash_add_ptr(target_function_table, lowercase_name, reg_function) == NULL) {
 			unload=1;
@@ -3161,8 +3161,8 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
 						zend_flf_capacity *= 2;
 					}
 					/* +1 for NULL terminator */
-					zend_flf_handlers = realloc(zend_flf_handlers, (zend_flf_capacity + 1) * sizeof(void *));
-					zend_flf_functions = realloc(zend_flf_functions, (zend_flf_capacity + 1) * sizeof(zend_function *));
+					zend_flf_handlers = perealloc(zend_flf_handlers, (zend_flf_capacity + 1) * sizeof(void *), true);
+					zend_flf_functions = perealloc(zend_flf_functions, (zend_flf_capacity + 1) * sizeof(zend_function *), true);
 				}
 				zend_flf_handlers[zend_flf_count] = flf_info->handler;
 				zend_flf_functions[zend_flf_count] = (zend_function *)reg_function;
@@ -3208,7 +3208,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend

 			/* Treat return type as an extra argument */
 			num_args++;
-			new_arg_info = malloc(sizeof(zend_arg_info) * num_args);
+			new_arg_info = pemalloc(sizeof(zend_arg_info) * num_args, true);
 			reg_function->arg_info = new_arg_info + 1;
 			for (i = 0; i < num_args; i++) {
 				zend_convert_internal_arg_info(&new_arg_info[i], &arg_info[i],
@@ -3493,7 +3493,7 @@ ZEND_API int zend_next_free_module(void) /* {{{ */

 static zend_class_entry *do_register_internal_class(const zend_class_entry *orig_class_entry, uint32_t ce_flags) /* {{{ */
 {
-	zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
+	zend_class_entry *class_entry = pemalloc(sizeof(zend_class_entry), true);
 	zend_string *lowercase_name;
 	*class_entry = *orig_class_entry;

diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c
index bf4c84404a6..d70d08f5f1c 100644
--- a/Zend/zend_inheritance.c
+++ b/Zend/zend_inheritance.c
@@ -1595,11 +1595,7 @@ static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_en

 	ce_num = ce->num_interfaces;

-	if (ce->type == ZEND_INTERNAL_CLASS) {
-		ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
-	} else {
-		ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
-	}
+	ce->interfaces = (zend_class_entry **) perealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num), ce->type == ZEND_INTERNAL_CLASS);

 	/* Inherit the interfaces, only if they're not already inherited by the class */
 	while (if_num--) {
@@ -2234,11 +2230,7 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry
 		} ZEND_HASH_FOREACH_END();
 	} else {
 		if (ce->num_interfaces >= current_iface_num) {
-			if (ce->type == ZEND_INTERNAL_CLASS) {
-				ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
-			} else {
-				ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
-			}
+			ce->interfaces = (zend_class_entry **) perealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num), ce->type == ZEND_INTERNAL_CLASS);
 		}
 		ce->interfaces[ce->num_interfaces++] = iface;

diff --git a/ext/opcache/zend_accelerator_blacklist.c b/ext/opcache/zend_accelerator_blacklist.c
index 56a4ceb4dc4..ed03a82e9f3 100644
--- a/ext/opcache/zend_accelerator_blacklist.c
+++ b/ext/opcache/zend_accelerator_blacklist.c
@@ -225,7 +225,7 @@ static inline void zend_accel_blacklist_allocate(zend_blacklist *blacklist)
 {
 	if (blacklist->pos == blacklist->size) {
 		blacklist->size += ZEND_BLACKLIST_BLOCK_SIZE;
-		blacklist->entries = (zend_blacklist_entry *) realloc(blacklist->entries, sizeof(zend_blacklist_entry)*blacklist->size);
+		blacklist->entries = (zend_blacklist_entry *) perealloc(blacklist->entries, sizeof(zend_blacklist_entry)*blacklist->size, true);
 	}
 }

diff --git a/main/network.c b/main/network.c
index f652cf555ff..90d1716b558 100644
--- a/main/network.c
+++ b/main/network.c
@@ -1459,7 +1459,7 @@ static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf

 	if (*hstbuflen == 0) {
 		*hstbuflen = 1024;
-		*tmphstbuf = (char *)malloc (*hstbuflen);
+		*tmphstbuf = (char *)pemalloc(*hstbuflen, true);
 	}

 	while (( res =
@@ -1467,7 +1467,7 @@ static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf
 		&& (errno == ERANGE)) {
 		/* Enlarge the buffer. */
 		*hstbuflen *= 2;
-		*tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
+		*tmphstbuf = (char *)perealloc(*tmphstbuf, *hstbuflen, true);
 	}

 	if (res != 0) {
@@ -1485,7 +1485,7 @@ static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf

 	if (*hstbuflen == 0) {
 		*hstbuflen = 1024;
-		*tmphstbuf = (char *)malloc (*hstbuflen);
+		*tmphstbuf = (char *)pemalloc(*hstbuflen, true);
 	}

 	while ((NULL == ( hp =
@@ -1493,7 +1493,7 @@ static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf
 		&& (errno == ERANGE)) {
 		/* Enlarge the buffer. */
 		*hstbuflen *= 2;
-		*tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
+		*tmphstbuf = (char *)perealloc(*tmphstbuf, *hstbuflen, true);
 	}
 	return hp;
 }
@@ -1503,11 +1503,11 @@ static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf
 {
 	if (*hstbuflen == 0) {
 		*hstbuflen = sizeof(struct hostent_data);
-		*tmphstbuf = (char *)malloc (*hstbuflen);
+		*tmphstbuf = (char *)pemalloc(*hstbuflen, true);
 	} else {
 		if (*hstbuflen < sizeof(struct hostent_data)) {
 			*hstbuflen = sizeof(struct hostent_data);
-			*tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen);
+			*tmphstbuf = (char *)perealloc(*tmphstbuf, *hstbuflen, true);
 		}
 	}
 	memset((void *)(*tmphstbuf),0,*hstbuflen);
diff --git a/main/php_ini.c b/main/php_ini.c
index 9925eafad1f..43e1c115e6e 100644
--- a/main/php_ini.c
+++ b/main/php_ini.c
@@ -694,7 +694,7 @@ void php_init_config(void)

 		if (total_l) {
 			size_t php_ini_scanned_files_len = (php_ini_scanned_files) ? strlen(php_ini_scanned_files) + 1 : 0;
-			php_ini_scanned_files = (char *) realloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1);
+			php_ini_scanned_files = (char *) perealloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1, true);
 			if (!php_ini_scanned_files_len) {
 				*php_ini_scanned_files = '\0';
 			}
diff --git a/main/php_ini_builder.h b/main/php_ini_builder.h
index 0ad70b6f68a..9f73cba13cb 100644
--- a/main/php_ini_builder.h
+++ b/main/php_ini_builder.h
@@ -60,7 +60,7 @@ static inline char *php_ini_builder_finish(struct php_ini_builder *b)
 static inline void php_ini_builder_realloc(struct php_ini_builder *b, size_t delta)
 {
 	/* reserve enough space for the null terminator */
-	b->value = realloc(b->value, b->length + delta + 1);
+	b->value = perealloc(b->value, b->length + delta + 1, true);
 }

 /**
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c
index 278e2657862..3c0d5e836dd 100644
--- a/sapi/phpdbg/phpdbg.c
+++ b/sapi/phpdbg/phpdbg.c
@@ -1199,9 +1199,9 @@ int main(int argc, char **argv) /* {{{ */
 			case 'z':
 				zend_extensions_len++;
 				if (zend_extensions_list) {
-					zend_extensions_list = realloc(zend_extensions_list, sizeof(char*) * zend_extensions_len);
+					zend_extensions_list = perealloc(zend_extensions_list, sizeof(char*) * zend_extensions_len, true);
 				} else {
-					zend_extensions_list = malloc(sizeof(char*) * zend_extensions_len);
+					zend_extensions_list = pemalloc(sizeof(char*) * zend_extensions_len, true);
 				}
 				zend_extensions_list[zend_extensions_len-1] = strdup(php_optarg);
 			break;
diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c
index 9435e25ca00..692cda32c7e 100644
--- a/sapi/phpdbg/phpdbg_prompt.c
+++ b/sapi/phpdbg/phpdbg_prompt.c
@@ -215,9 +215,9 @@ static void phpdbg_line_init(char *cmd, struct phpdbg_init_state *state) {

 		if (state->in_code) {
 			if (state->code == NULL) {
-				state->code = malloc(cmd_len + 1);
+				state->code = pemalloc(cmd_len + 1, true);
 			} else {
-				state->code = realloc(state->code, state->code_len + cmd_len + 1);
+				state->code = perealloc(state->code, state->code_len + cmd_len + 1, true);
 			}

 			if (state->code) {