Fix handling of references in zval_try_get_long()

This API can't handle references, yet everyone keeps forgetting that it
can't and that you should DEREF upfront. Fix every type of this issue
once and for all by moving the reference handling to this Zend API.

Closes GH-18761.
This commit is contained in:
Niels Dossche 2025-06-04 19:52:21 +02:00
parent 111072a9f0
commit 2b383848a7
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
6 changed files with 27 additions and 8 deletions

1
NEWS
View file

@ -12,6 +12,7 @@ PHP NEWS
released on bailout). (DanielEScherzer and ilutov) released on bailout). (DanielEScherzer and ilutov)
. Fixed GH-18695 (zend_ast_export() - float number is not preserved). . Fixed GH-18695 (zend_ast_export() - float number is not preserved).
(Oleg Efimov) (Oleg Efimov)
. Fix handling of references in zval_try_get_long(). (nielsdos)
- Curl: - Curl:
. Fix memory leak when setting a list via curl_setopt fails. (nielsdos) . Fix memory leak when setting a list via curl_setopt fails. (nielsdos)

View file

@ -378,6 +378,7 @@ static zend_always_inline zend_result zendi_try_convert_scalar_to_number(zval *o
static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(const zval *op, bool *failed) /* {{{ */ static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(const zval *op, bool *failed) /* {{{ */
{ {
*failed = 0; *failed = 0;
try_again:
switch (Z_TYPE_P(op)) { switch (Z_TYPE_P(op)) {
case IS_NULL: case IS_NULL:
case IS_FALSE: case IS_FALSE:
@ -448,6 +449,14 @@ static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(const zval *
case IS_ARRAY: case IS_ARRAY:
*failed = 1; *failed = 1;
return 0; return 0;
case IS_REFERENCE:
op = Z_REFVAL_P(op);
if (Z_TYPE_P(op) == IS_LONG) {
return Z_LVAL_P(op);
} else {
goto try_again;
}
break;
EMPTY_SWITCH_DEFAULT_CASE() EMPTY_SWITCH_DEFAULT_CASE()
} }
} }

View file

@ -185,12 +185,10 @@ PHP_METHOD(IntlDateFormatter, parseToCalendar)
DATE_FORMAT_METHOD_FETCH_OBJECT; DATE_FORMAT_METHOD_FETCH_OBJECT;
if (z_parse_pos) { if (z_parse_pos) {
zval *z_parse_pos_tmp = z_parse_pos; bool failed;
ZVAL_DEREF(z_parse_pos_tmp); zend_long long_parse_pos = zval_try_get_long(z_parse_pos, &failed);
bool failed = false;
zend_long long_parse_pos = zval_try_get_long(z_parse_pos_tmp, &failed);
if (failed) { if (failed) {
zend_argument_type_error(2, "must be of type int, %s given", zend_zval_value_name(z_parse_pos_tmp)); zend_argument_type_error(2, "must be of type int, %s given", zend_zval_value_name(z_parse_pos));
RETURN_THROWS(); RETURN_THROWS();
} }
if (ZEND_LONG_INT_OVFL(long_parse_pos)) { if (ZEND_LONG_INT_OVFL(long_parse_pos)) {

View file

@ -3930,7 +3930,7 @@ static uint32_t *make_conversion_map(HashTable *target_hash, size_t *conversion_
uint32_t *mapelm = convmap; uint32_t *mapelm = convmap;
ZEND_HASH_FOREACH_VAL(target_hash, hash_entry) { ZEND_HASH_FOREACH_VAL(target_hash, hash_entry) {
bool failed = true; bool failed;
zend_long tmp = zval_try_get_long(hash_entry, &failed); zend_long tmp = zval_try_get_long(hash_entry, &failed);
if (failed) { if (failed) {
efree(convmap); efree(convmap);

View file

@ -0,0 +1,12 @@
--TEST--
mb_encode_numericentity() reference handling
--EXTENSIONS--
mbstring
--FILE--
<?php
$n = 0;
$convmap = [&$n, 0x1FFFFF, 0, 0x10FFFF];
var_dump(mb_encode_numericentity("", $convmap, "utf8"));
?>
--EXPECT--
string(0) ""

View file

@ -874,8 +874,7 @@ static bool php_pcntl_set_user_signal_infos(
zval *user_signal_no; zval *user_signal_no;
ZEND_HASH_FOREACH_VAL(user_signals, user_signal_no) { ZEND_HASH_FOREACH_VAL(user_signals, user_signal_no) {
bool failed = true; bool failed;
ZVAL_DEREF(user_signal_no);
zend_long tmp = zval_try_get_long(user_signal_no, &failed); zend_long tmp = zval_try_get_long(user_signal_no, &failed);
if (failed) { if (failed) {