From b1340ddf94108b36036f7070bb43f68126cc626c Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Fri, 24 Apr 2026 10:14:07 +0800 Subject: [PATCH 1/4] inital fix --- NEWS | 3 +- UPGRADING | 2 +- .../deflate_init_strategy_type_error.phpt | 23 ++++++++- ext/zlib/zlib.c | 50 ++++++++++++------- 4 files changed, 56 insertions(+), 22 deletions(-) diff --git a/NEWS b/NEWS index d26148877670..2ed74ba04639 100644 --- a/NEWS +++ b/NEWS @@ -199,6 +199,7 @@ PHP NEWS - Zlib: . deflate_init() now raises a TypeError when the value for option - "strategy" is not of type int. (Weilin Du) + "level", "memory", "window", or "strategy" is not of type int. + (Weilin Du) <<< NOTE: Insert NEWS from last stable release here prior to actual release! >>> diff --git a/UPGRADING b/UPGRADING index 6c6115ebcc84..6db70ded903a 100644 --- a/UPGRADING +++ b/UPGRADING @@ -103,7 +103,7 @@ PHP 8.6 UPGRADE NOTES - Zlib: . deflate_init() now raises a TypeError when the value for option - "strategy" is not of type int. + "level", "memory", "window", or "strategy" is not of type int. ======================================== 2. New Features diff --git a/ext/zlib/tests/deflate_init_strategy_type_error.phpt b/ext/zlib/tests/deflate_init_strategy_type_error.phpt index 0227d1bf6c29..cdf4c2021860 100644 --- a/ext/zlib/tests/deflate_init_strategy_type_error.phpt +++ b/ext/zlib/tests/deflate_init_strategy_type_error.phpt @@ -1,10 +1,28 @@ --TEST-- -deflate_init(): strategy option type validation +deflate_init(): options type validation --EXTENSIONS-- zlib --FILE-- []]); +} catch (TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + deflate_init(ZLIB_ENCODING_DEFLATE, ['memory' => []]); +} catch (TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + deflate_init(ZLIB_ENCODING_DEFLATE, ['window' => []]); +} catch (TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} + try { deflate_init(ZLIB_ENCODING_DEFLATE, ['strategy' => []]); } catch (TypeError $e) { @@ -13,4 +31,7 @@ try { ?> --EXPECT-- +deflate_init(): Argument #2 ($options) the value for option "level" must be of type int, array given +deflate_init(): Argument #2 ($options) the value for option "memory" must be of type int, array given +deflate_init(): Argument #2 ($options) the value for option "window" must be of type int, array given deflate_init(): Argument #2 ($options) the value for option "strategy" must be of type int, array given diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 115eedbc894a..11c0a1329884 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -854,6 +854,29 @@ static bool zlib_create_dictionary_string(HashTable *options, char **dict, size_ return true; } +static bool zlib_get_long_option(HashTable *options, const char *option_name, size_t option_name_len, zend_long *value) +{ + zval *option_buffer; + bool failed = false; + + if (!options || (option_buffer = zend_hash_str_find(options, option_name, option_name_len)) == NULL) { + return true; + } + + ZVAL_DEINDIRECT(option_buffer); + *value = zval_try_get_long(option_buffer, &failed); + if (UNEXPECTED(failed)) { + zend_argument_type_error( + 2, + "the value for option \"%.*s\" must be of type int, %s given", + (int) option_name_len, option_name, zend_zval_value_name(option_buffer) + ); + return false; + } + + return true; +} + /* {{{ Initialize an incremental inflate context with the specified encoding */ PHP_FUNCTION(inflate_init) { @@ -1081,48 +1104,37 @@ PHP_FUNCTION(deflate_init) char *dict = NULL; size_t dictlen = 0; HashTable *options = NULL; - zval *option_buffer; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|H", &encoding, &options)) { RETURN_THROWS(); } - if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("level"))) != NULL) { - ZVAL_DEINDIRECT(option_buffer); - level = zval_get_long(option_buffer); + if (!zlib_get_long_option(options, ZEND_STRL("level"), &level)) { + RETURN_THROWS(); } if (level < -1 || level > 9) { zend_value_error("deflate_init(): \"level\" option must be between -1 and 9"); RETURN_THROWS(); } - if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("memory"))) != NULL) { - ZVAL_DEINDIRECT(option_buffer); - memory = zval_get_long(option_buffer); + if (!zlib_get_long_option(options, ZEND_STRL("memory"), &memory)) { + RETURN_THROWS(); } if (memory < 1 || memory > 9) { zend_value_error("deflate_init(): \"memory\" option must be between 1 and 9"); RETURN_THROWS(); } - if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("window"))) != NULL) { - ZVAL_DEINDIRECT(option_buffer); - window = zval_get_long(option_buffer); + if (!zlib_get_long_option(options, ZEND_STRL("window"), &window)) { + RETURN_THROWS(); } if (window < 8 || window > 15) { zend_value_error("deflate_init(): \"window\" option must be between 8 and 15"); RETURN_THROWS(); } - if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("strategy"))) != NULL) { - bool failed = false; - - ZVAL_DEINDIRECT(option_buffer); - strategy = zval_try_get_long(option_buffer, &failed); - if (UNEXPECTED(failed)) { - zend_argument_type_error(2, "the value for option \"strategy\" must be of type int, %s given", zend_zval_value_name(option_buffer)); - RETURN_THROWS(); - } + if (!zlib_get_long_option(options, ZEND_STRL("strategy"), &strategy)) { + RETURN_THROWS(); } switch (strategy) { case Z_FILTERED: From b06bea79a2ea700041b5ffd7c338a6a89c2508c1 Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Fri, 24 Apr 2026 12:48:19 +0800 Subject: [PATCH 2/4] Use variety types in test --- .../tests/deflate_init_strategy_type_error.phpt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ext/zlib/tests/deflate_init_strategy_type_error.phpt b/ext/zlib/tests/deflate_init_strategy_type_error.phpt index cdf4c2021860..2a59082bc320 100644 --- a/ext/zlib/tests/deflate_init_strategy_type_error.phpt +++ b/ext/zlib/tests/deflate_init_strategy_type_error.phpt @@ -5,8 +5,11 @@ zlib --FILE-- []]); + deflate_init(ZLIB_ENCODING_DEFLATE, ['level' => 'foo']); } catch (TypeError $e) { echo $e->getMessage(), PHP_EOL; } @@ -18,20 +21,22 @@ try { } try { - deflate_init(ZLIB_ENCODING_DEFLATE, ['window' => []]); + deflate_init(ZLIB_ENCODING_DEFLATE, ['window' => new A()]); } catch (TypeError $e) { echo $e->getMessage(), PHP_EOL; } try { - deflate_init(ZLIB_ENCODING_DEFLATE, ['strategy' => []]); + deflate_init(ZLIB_ENCODING_DEFLATE, ['strategy' => $fp]); } catch (TypeError $e) { echo $e->getMessage(), PHP_EOL; } +fclose($fp); + ?> --EXPECT-- -deflate_init(): Argument #2 ($options) the value for option "level" must be of type int, array given +deflate_init(): Argument #2 ($options) the value for option "level" must be of type int, string given deflate_init(): Argument #2 ($options) the value for option "memory" must be of type int, array given -deflate_init(): Argument #2 ($options) the value for option "window" must be of type int, array given -deflate_init(): Argument #2 ($options) the value for option "strategy" must be of type int, array given +deflate_init(): Argument #2 ($options) the value for option "window" must be of type int, A given +deflate_init(): Argument #2 ($options) the value for option "strategy" must be of type int, resource given From f015d01fe2a8626a4542485d605cc953830ec4f4 Mon Sep 17 00:00:00 2001 From: Weilin Du <108666168+LamentXU123@users.noreply.github.com> Date: Mon, 27 Apr 2026 22:16:53 +0800 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Gina Peter Banyard --- ext/zlib/zlib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 11c0a1329884..c52d63efe76d 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -854,12 +854,12 @@ static bool zlib_create_dictionary_string(HashTable *options, char **dict, size_ return true; } -static bool zlib_get_long_option(HashTable *options, const char *option_name, size_t option_name_len, zend_long *value) +ZEND_ATTRIBUTE_NONNULL static bool zlib_get_long_option(HashTable *options, const char *option_name, size_t option_name_len, zend_long *value) { - zval *option_buffer; bool failed = false; + zval *option_buffer = zend_hash_str_find(options, option_name, option_name_len); - if (!options || (option_buffer = zend_hash_str_find(options, option_name, option_name_len)) == NULL) { + if (!option_buffer) { return true; } @@ -1103,7 +1103,7 @@ PHP_FUNCTION(deflate_init) zend_long encoding, level = -1, memory = 8, window = 15, strategy = Z_DEFAULT_STRATEGY; char *dict = NULL; size_t dictlen = 0; - HashTable *options = NULL; + HashTable *options = (HashTable*)&zend_empty_array; if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|H", &encoding, &options)) { RETURN_THROWS(); From 449ba043db14aeb89e645126d4c89e463801446b Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Mon, 27 Apr 2026 22:18:32 +0800 Subject: [PATCH 4/4] add comments to make things clear --- ext/zlib/zlib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index c52d63efe76d..0a8f21c41a70 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -863,6 +863,7 @@ ZEND_ATTRIBUTE_NONNULL static bool zlib_get_long_option(HashTable *options, cons return true; } + /* The |H ZPP specifier may leave HashTable entries wrapped in IS_INDIRECT. */ ZVAL_DEINDIRECT(option_buffer); *value = zval_try_get_long(option_buffer, &failed); if (UNEXPECTED(failed)) {