diff --git a/NEWS b/NEWS index b7b7482bfda3e..9a0244ae86383 100644 --- a/NEWS +++ b/NEWS @@ -50,6 +50,10 @@ PHP NEWS . Fixed bug GH-16292 (Segmentation fault in ext/xmlreader/php_xmlreader.c). (nielsdos) +- Zlib: + . Fixed bug GH-16326 (Memory management is broken for bad dictionaries.) + (cmb) + 24 Oct 2024, PHP 8.3.13 - Calendar: diff --git a/ext/zlib/tests/gh16326.phpt b/ext/zlib/tests/gh16326.phpt new file mode 100644 index 0000000000000..b4997368549f7 --- /dev/null +++ b/ext/zlib/tests/gh16326.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-16326 (Memory management is broken for bad dictionaries) +--EXTENSIONS-- +zlib +--FILE-- + [" ", ""]]); +} 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 diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 8b593f1f451b0..cfa8eefb47461 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -805,35 +805,29 @@ static bool zlib_create_dictionary_string(HashTable *options, char **dict, size_ if (zend_hash_num_elements(dictionary) > 0) { char *dictptr; 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_HASH_FOREACH_VAL(dictionary, cur) { - size_t i; - *++ptr = zval_get_string(cur); - if (!*ptr || ZSTR_LEN(*ptr) == 0 || EG(exception)) { - if (*ptr) { - efree(*ptr); - } - while (--ptr >= strings) { - efree(ptr); - } + ZEND_ASSERT(*ptr); + if (ZSTR_LEN(*ptr) == 0 || EG(exception)) { + do { + zend_string_release(*ptr); + } while (--ptr >= strings); efree(strings); if (!EG(exception)) { zend_argument_value_error(2, "must not contain empty strings"); } return 0; } - for (i = 0; i < ZSTR_LEN(*ptr); i++) { - if (ZSTR_VAL(*ptr)[i] == 0) { - do { - efree(ptr); - } while (--ptr >= strings); - efree(strings); - zend_argument_value_error(2, "must not contain strings with null bytes"); - return 0; - } + if (zend_str_has_nul_byte(*ptr)) { + do { + zend_string_release(*ptr); + } while (--ptr >= strings); + efree(strings); + zend_argument_value_error(2, "must not contain strings with null bytes"); + return 0; } *dictlen += ZSTR_LEN(*ptr) + 1;