[php-src] Issue #24068: ext/standard: conversion of uint32_t __fill_idx to zend_long in ZEND_HASH_FILL_FINISH() as used in php_array_merge_wrapper()

From: Date: Fri, 02 Oct 2026 05:40:56 +0000
Subject: [php-src] Issue #24068: ext/standard: conversion of uint32_t __fill_idx to zend_long in ZEND_HASH_FILL_FINISH() as used in php_array_merge_wrapper()
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-252881@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/24068 Author: ushevchenko ### Description ZEND_HASH_FILL_FINISH() in Zend/zend_hash.h assigns the uint32_t counter __fill_idx to the zend_long field nNextFreeElement: #define ZEND_HASH_FILL_FINISH() do { \ __fill_ht->nNumOfElements += __fill_idx - __fill_ht->nNumUsed; \ __fill_ht->nNumUsed = __fill_idx; \ __fill_ht->nNextFreeElement = __fill_idx; \ __fill_ht->nInternalPointer = 0; \ } while (0) A static analyzer (SVACE, SIGN_EXTENSION) reports this as an unsafe uint32_t -> zend_long conversion: if __fill_idx were greater than INT_MAX, the result would differ between 32-bit platforms (long is 32-bit, the value becomes negative) and 64-bit platforms (long is 64-bit, the value is zero-extended). It is reported for the use in php_array_merge_wrapper() in ext/standard/array.c: array_init_size(return_value, count); dest = Z_ARRVAL_P(return_value); zend_hash_real_init_packed(dest); ZEND_HASH_FILL_PACKED(dest) { ZEND_HASH_PACKED_FOREACH_VAL(src, src_entry) { ... ZEND_HASH_FILL_ADD(src_entry); } ZEND_HASH_FOREACH_END(); } ZEND_HASH_FILL_END(); Reachability. I did not reproduce a problem; this report is based on reading the code. I believe the conversion cannot overflow here: - __fill_idx starts at nNumUsed of the newly created array (0) and is incremented once per element of src, so __fill_idx <= zend_hash_num_elements(src) <= count. - count is the sum of zend_hash_num_elements() over all arguments, and the function throws "The total number of elements must be lower than %u" if count >= HT_MAX_SIZE. - HT_MAX_SIZE is 0x40000000 on 64-bit and 0x02000000 on 32-bit platforms (Zend/zend_types.h), both smaller than INT_MAX. So __fill_idx < HT_MAX_SIZE < INT_MAX, and the value is the same after the conversion on every platform. Question. Is this analysis correct, i.e. can the conversion in ZEND_HASH_FILL_FINISH() be considered safe here? If so, I will treat the report as a false positive. The same warning is reported for other uses of ZEND_HASH_FILL_END() in ext/standard/array.c; I have analyzed only php_array_merge_wrapper(). Found by Linux Verification Center (https://portal.linuxtesting.ru) using SVACE. Author U. Shevchenko. ### PHP Version ```plain 8.3.31 (static analysis of the source, not run); the same code is present in master ``` ### Operating System N/A (static analysis)

« previous php.bugs (#252881) next »