Skip to content

Commit cde419a

Browse files
committed
Fix GH-19200: replace unchecked realloc/malloc with perealloc/pemalloc
Raw realloc() returns NULL on allocation failure, losing the original pointer and causing a crash on the next dereference. pemalloc/perealloc with persistent=1 wrap the system allocator but call zend_out_of_memory() on failure, giving a clean exit instead of an undefined crash. Converts all V701 locations from the PVS-Studio report and unchecked malloc calls in zend_register_functions() (GH-17013). Skips zend_alloc.c (already handled) and IR JIT code (third-party). The zend_inheritance.c changes also simplify the realloc/erealloc branch into a single perealloc() call, matching the existing pattern at zend_implement_stringable(). Fixes GH-19200 Closes GH-17013
1 parent 9c08243 commit cde419a

File tree

9 files changed

+27
-35
lines changed

9 files changed

+27
-35
lines changed

Zend/zend.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,7 @@ ZEND_API void zend_append_version_info(const zend_extension *extension) /* {{{ *
12961296

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

1299-
zend_version_info = (char *) realloc(zend_version_info, zend_version_info_length+new_info_length + 1);
1299+
zend_version_info = (char *) perealloc(zend_version_info, zend_version_info_length+new_info_length + 1, 1);
13001300
strncat(zend_version_info, new_info, new_info_length);
13011301
zend_version_info_length += new_info_length;
13021302
free(new_info);

Zend/zend_API.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,19 +2522,19 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
25222522
dl_loaded_count++;
25232523
}
25242524
} ZEND_HASH_FOREACH_END();
2525-
module_request_startup_handlers = (zend_module_entry**)realloc(
2525+
module_request_startup_handlers = (zend_module_entry**)perealloc(
25262526
module_request_startup_handlers,
25272527
sizeof(zend_module_entry*) *
25282528
(startup_count + 1 +
25292529
shutdown_count + 1 +
2530-
post_deactivate_count + 1));
2530+
post_deactivate_count + 1), 1);
25312531
module_request_startup_handlers[startup_count] = NULL;
25322532
module_request_shutdown_handlers = module_request_startup_handlers + startup_count + 1;
25332533
module_request_shutdown_handlers[shutdown_count] = NULL;
25342534
module_post_deactivate_handlers = module_request_shutdown_handlers + shutdown_count + 1;
25352535
module_post_deactivate_handlers[post_deactivate_count] = NULL;
25362536
/* Cannot reuse module_request_startup_handlers because it is freed in zend_destroy_modules, which happens before zend_unload_modules. */
2537-
modules_dl_loaded = realloc(modules_dl_loaded, sizeof(zend_module_entry*) * (dl_loaded_count + 1));
2537+
modules_dl_loaded = perealloc(modules_dl_loaded, sizeof(zend_module_entry*) * (dl_loaded_count + 1), 1);
25382538
modules_dl_loaded[dl_loaded_count] = NULL;
25392539
startup_count = 0;
25402540

@@ -2561,10 +2561,10 @@ ZEND_API void zend_collect_module_handlers(void) /* {{{ */
25612561
}
25622562
} ZEND_HASH_FOREACH_END();
25632563

2564-
class_cleanup_handlers = (zend_class_entry**)realloc(
2564+
class_cleanup_handlers = (zend_class_entry**)perealloc(
25652565
class_cleanup_handlers,
25662566
sizeof(zend_class_entry*) *
2567-
(class_count + 1));
2567+
(class_count + 1), 1);
25682568
class_cleanup_handlers[class_count] = NULL;
25692569

25702570
if (class_count) {
@@ -3076,7 +3076,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
30763076
}
30773077
lowercase_name = zend_string_tolower_ex(internal_function->function_name, type == MODULE_PERSISTENT);
30783078
lowercase_name = zend_new_interned_string(lowercase_name);
3079-
reg_function = malloc(sizeof(zend_internal_function));
3079+
reg_function = pemalloc(sizeof(zend_internal_function), 1);
30803080
memcpy(reg_function, &function, sizeof(zend_internal_function));
30813081
if (zend_hash_add_ptr(target_function_table, lowercase_name, reg_function) == NULL) {
30823082
unload=1;
@@ -3094,8 +3094,8 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
30943094
zend_flf_capacity *= 2;
30953095
}
30963096
/* +1 for NULL terminator */
3097-
zend_flf_handlers = realloc(zend_flf_handlers, (zend_flf_capacity + 1) * sizeof(void *));
3098-
zend_flf_functions = realloc(zend_flf_functions, (zend_flf_capacity + 1) * sizeof(zend_function *));
3097+
zend_flf_handlers = perealloc(zend_flf_handlers, (zend_flf_capacity + 1) * sizeof(void *), 1);
3098+
zend_flf_functions = perealloc(zend_flf_functions, (zend_flf_capacity + 1) * sizeof(zend_function *), 1);
30993099
}
31003100
zend_flf_handlers[zend_flf_count] = flf_info->handler;
31013101
zend_flf_functions[zend_flf_count] = (zend_function *)reg_function;
@@ -3143,7 +3143,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
31433143

31443144
/* Treat return type as an extra argument */
31453145
num_args++;
3146-
new_arg_info = malloc(sizeof(zend_internal_arg_info) * num_args);
3146+
new_arg_info = pemalloc(sizeof(zend_internal_arg_info) * num_args, 1);
31473147
memcpy(new_arg_info, arg_info, sizeof(zend_internal_arg_info) * num_args);
31483148
reg_function->arg_info = new_arg_info + 1;
31493149
for (i = 0; i < num_args; i++) {
@@ -3169,7 +3169,7 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
31693169
new_arg_info[i].type.type_mask |= _ZEND_TYPE_NAME_BIT;
31703170
} else {
31713171
/* Union type */
3172-
zend_type_list *list = malloc(ZEND_TYPE_LIST_SIZE(num_types));
3172+
zend_type_list *list = pemalloc(ZEND_TYPE_LIST_SIZE(num_types), 1);
31733173
list->num_types = num_types;
31743174
ZEND_TYPE_SET_LIST(new_arg_info[i].type, list);
31753175
ZEND_TYPE_FULL_MASK(new_arg_info[i].type) |= _ZEND_TYPE_UNION_BIT;
@@ -3480,7 +3480,7 @@ ZEND_API int zend_next_free_module(void) /* {{{ */
34803480

34813481
static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class_entry, uint32_t ce_flags) /* {{{ */
34823482
{
3483-
zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
3483+
zend_class_entry *class_entry = pemalloc(sizeof(zend_class_entry), 1);
34843484
zend_string *lowercase_name;
34853485
*class_entry = *orig_class_entry;
34863486

Zend/zend_inheritance.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,11 +1573,7 @@ static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_en
15731573

15741574
ce_num = ce->num_interfaces;
15751575

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

15821578
/* Inherit the interfaces, only if they're not already inherited by the class */
15831579
while (if_num--) {
@@ -2206,11 +2202,7 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry
22062202
} ZEND_HASH_FOREACH_END();
22072203
} else {
22082204
if (ce->num_interfaces >= current_iface_num) {
2209-
if (ce->type == ZEND_INTERNAL_CLASS) {
2210-
ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2211-
} else {
2212-
ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2213-
}
2205+
ce->interfaces = (zend_class_entry **) perealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num), ce->type == ZEND_INTERNAL_CLASS);
22142206
}
22152207
ce->interfaces[ce->num_interfaces++] = iface;
22162208

ext/opcache/zend_accelerator_blacklist.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ static inline void zend_accel_blacklist_allocate(zend_blacklist *blacklist)
233233
{
234234
if (blacklist->pos == blacklist->size) {
235235
blacklist->size += ZEND_BLACKLIST_BLOCK_SIZE;
236-
blacklist->entries = (zend_blacklist_entry *) realloc(blacklist->entries, sizeof(zend_blacklist_entry)*blacklist->size);
236+
blacklist->entries = (zend_blacklist_entry *) perealloc(blacklist->entries, sizeof(zend_blacklist_entry)*blacklist->size, 1);
237237
}
238238
}
239239

main/network.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,15 +1345,15 @@ static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf
13451345

13461346
if (*hstbuflen == 0) {
13471347
*hstbuflen = 1024;
1348-
*tmphstbuf = (char *)malloc (*hstbuflen);
1348+
*tmphstbuf = (char *)pemalloc(*hstbuflen, 1);
13491349
}
13501350

13511351
while (( res =
13521352
gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr))
13531353
&& (errno == ERANGE)) {
13541354
/* Enlarge the buffer. */
13551355
*hstbuflen *= 2;
1356-
*tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
1356+
*tmphstbuf = (char *)perealloc(*tmphstbuf, *hstbuflen, 1);
13571357
}
13581358

13591359
if (res != 0) {
@@ -1371,15 +1371,15 @@ static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf
13711371

13721372
if (*hstbuflen == 0) {
13731373
*hstbuflen = 1024;
1374-
*tmphstbuf = (char *)malloc (*hstbuflen);
1374+
*tmphstbuf = (char *)pemalloc(*hstbuflen, 1);
13751375
}
13761376

13771377
while ((NULL == ( hp =
13781378
gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr)))
13791379
&& (errno == ERANGE)) {
13801380
/* Enlarge the buffer. */
13811381
*hstbuflen *= 2;
1382-
*tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
1382+
*tmphstbuf = (char *)perealloc(*tmphstbuf, *hstbuflen, 1);
13831383
}
13841384
return hp;
13851385
}
@@ -1389,11 +1389,11 @@ static struct hostent * gethostname_re (const char *host,struct hostent *hostbuf
13891389
{
13901390
if (*hstbuflen == 0) {
13911391
*hstbuflen = sizeof(struct hostent_data);
1392-
*tmphstbuf = (char *)malloc (*hstbuflen);
1392+
*tmphstbuf = (char *)pemalloc(*hstbuflen, 1);
13931393
} else {
13941394
if (*hstbuflen < sizeof(struct hostent_data)) {
13951395
*hstbuflen = sizeof(struct hostent_data);
1396-
*tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen);
1396+
*tmphstbuf = (char *)perealloc(*tmphstbuf, *hstbuflen, 1);
13971397
}
13981398
}
13991399
memset((void *)(*tmphstbuf),0,*hstbuflen);

main/php_ini.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ int php_init_config(void)
699699

700700
if (total_l) {
701701
int php_ini_scanned_files_len = (php_ini_scanned_files) ? (int)strlen(php_ini_scanned_files) + 1 : 0;
702-
php_ini_scanned_files = (char *) realloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1);
702+
php_ini_scanned_files = (char *) perealloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1, 1);
703703
if (!php_ini_scanned_files_len) {
704704
*php_ini_scanned_files = '\0';
705705
}

main/php_ini_builder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ static inline char *php_ini_builder_finish(struct php_ini_builder *b)
6262
static inline void php_ini_builder_realloc(struct php_ini_builder *b, size_t delta)
6363
{
6464
/* reserve enough space for the null terminator */
65-
b->value = realloc(b->value, b->length + delta + 1);
65+
b->value = perealloc(b->value, b->length + delta + 1, 1);
6666
}
6767

6868
/**

sapi/phpdbg/phpdbg.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,8 +1207,8 @@ int main(int argc, char **argv) /* {{{ */
12071207
case 'z':
12081208
zend_extensions_len++;
12091209
if (zend_extensions) {
1210-
zend_extensions = realloc(zend_extensions, sizeof(char*) * zend_extensions_len);
1211-
} else zend_extensions = malloc(sizeof(char*) * zend_extensions_len);
1210+
zend_extensions = perealloc(zend_extensions, sizeof(char*) * zend_extensions_len, 1);
1211+
} else zend_extensions = pemalloc(sizeof(char*) * zend_extensions_len, 1);
12121212
zend_extensions[zend_extensions_len-1] = strdup(php_optarg);
12131213
break;
12141214

sapi/phpdbg/phpdbg_prompt.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,9 @@ static void phpdbg_line_init(char *cmd, struct phpdbg_init_state *state) {
240240

241241
if (state->in_code) {
242242
if (state->code == NULL) {
243-
state->code = malloc(cmd_len + 1);
243+
state->code = pemalloc(cmd_len + 1, 1);
244244
} else {
245-
state->code = realloc(state->code, state->code_len + cmd_len + 1);
245+
state->code = perealloc(state->code, state->code_len + cmd_len + 1, 1);
246246
}
247247

248248
if (state->code) {

0 commit comments

Comments
 (0)