Merge branch 'PHP-8.3' into PHP-8.4

* PHP-8.3:
  Fix GH-16326: Memory management is broken for bad dictionaries
This commit is contained in:
Christoph M. Becker 2024-10-13 02:30:22 +02:00
commit a7918a7ac3
No known key found for this signature in database
GPG key ID: D66C9593118BCCB6
3 changed files with 43 additions and 19 deletions

4
NEWS
View file

@ -54,6 +54,10 @@ PHP NEWS
. Fixed bug GH-16292 (Segmentation fault in ext/xmlreader/php_xmlreader.c). . Fixed bug GH-16292 (Segmentation fault in ext/xmlreader/php_xmlreader.c).
(nielsdos) (nielsdos)
- Zlib:
. Fixed bug GH-16326 (Memory management is broken for bad dictionaries.)
(cmb)
10 Oct 2024, PHP 8.4.0RC2 10 Oct 2024, PHP 8.4.0RC2
- CGI: - CGI:

View file

@ -0,0 +1,26 @@
--TEST--
GH-16326 (Memory management is broken for bad dictionaries)
--EXTENSIONS--
zlib
--FILE--
<?php
try {
deflate_init(ZLIB_ENCODING_DEFLATE, ["dictionary" => [" ", ""]]);
} catch (ValueError $ex) {
echo $ex->getMessage(), "\n";
}
try {
deflate_init(ZLIB_ENCODING_DEFLATE, ["dictionary" => ["hello", "wor\0ld"]]);
} catch (ValueError $ex) {
echo $ex->getMessage(), "\n";
}
try {
deflate_init(ZLIB_ENCODING_DEFLATE, ["dictionary" => [" ", new stdClass]]);
} catch (Error $ex) {
echo $ex->getMessage(), "\n";
}
?>
--EXPECT--
deflate_init(): Argument #2 ($options) must not contain empty strings
deflate_init(): Argument #2 ($options) must not contain strings with null bytes
Object of class stdClass could not be converted to string

View file

@ -804,35 +804,29 @@ static bool zlib_create_dictionary_string(HashTable *options, char **dict, size_
if (zend_hash_num_elements(dictionary) > 0) { if (zend_hash_num_elements(dictionary) > 0) {
char *dictptr; char *dictptr;
zval *cur; zval *cur;
zend_string **strings = emalloc(sizeof(zend_string *) * zend_hash_num_elements(dictionary)); zend_string **strings = safe_emalloc(zend_hash_num_elements(dictionary), sizeof(zend_string *), 0);
zend_string **end, **ptr = strings - 1; zend_string **end, **ptr = strings - 1;
ZEND_HASH_FOREACH_VAL(dictionary, cur) { ZEND_HASH_FOREACH_VAL(dictionary, cur) {
size_t i;
*++ptr = zval_get_string(cur); *++ptr = zval_get_string(cur);
if (!*ptr || ZSTR_LEN(*ptr) == 0 || EG(exception)) { ZEND_ASSERT(*ptr);
if (*ptr) { if (ZSTR_LEN(*ptr) == 0 || EG(exception)) {
efree(*ptr); do {
} zend_string_release(*ptr);
while (--ptr >= strings) { } while (--ptr >= strings);
efree(ptr);
}
efree(strings); efree(strings);
if (!EG(exception)) { if (!EG(exception)) {
zend_argument_value_error(2, "must not contain empty strings"); zend_argument_value_error(2, "must not contain empty strings");
} }
return 0; return 0;
} }
for (i = 0; i < ZSTR_LEN(*ptr); i++) { if (zend_str_has_nul_byte(*ptr)) {
if (ZSTR_VAL(*ptr)[i] == 0) { do {
do { zend_string_release(*ptr);
efree(ptr); } while (--ptr >= strings);
} while (--ptr >= strings); efree(strings);
efree(strings); zend_argument_value_error(2, "must not contain strings with null bytes");
zend_argument_value_error(2, "must not contain strings with null bytes"); return 0;
return 0;
}
} }
*dictlen += ZSTR_LEN(*ptr) + 1; *dictlen += ZSTR_LEN(*ptr) + 1;