Merge branch 'PHP-8.4'

* PHP-8.4:
  NEWS for GH-16196
  NEWS for GH-16196
  NEWS for GH-16196
  Handle references properties of the Exception class
This commit is contained in:
Arnaud Le Blanc 2024-10-07 15:06:37 +02:00
commit 6c5749f34a
No known key found for this signature in database
GPG key ID: 0098C05DD15ABC13
2 changed files with 43 additions and 3 deletions

34
Zend/tests/gh16188.phpt Normal file
View file

@ -0,0 +1,34 @@
--TEST--
GH-16188 (Assertion failure in Zend/zend_exceptions.c)
--FILE--
<?php
$re = new TypeError();
array_walk($re, function (&$item, $key) use (&$re) {
if ($key === "\x00Error\x00previous") {
$item = new Exception();
}
});
printf("getTraceAsString:\n%s\n\n", $re->getTraceAsString());
printf("getPrevious:\n%s\n\n", get_class($re->getPrevious()));
printf("__toString:\n%s\n\n", $re);
?>
==DONE==
--EXPECTF--
getTraceAsString:
#0 {main}
getPrevious:
Exception
__toString:
Exception in %s:%d
Stack trace:%A
#%d {main}
Next TypeError in %s:%d
Stack trace:%A
#%d {main}
==DONE==

View file

@ -116,15 +116,18 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo
ex = &zv; ex = &zv;
do { do {
ancestor = zend_read_property_ex(i_get_exception_base(add_previous), add_previous, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); ancestor = zend_read_property_ex(i_get_exception_base(add_previous), add_previous, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
ZVAL_DEREF(ancestor);
while (Z_TYPE_P(ancestor) == IS_OBJECT) { while (Z_TYPE_P(ancestor) == IS_OBJECT) {
if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) { if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) {
OBJ_RELEASE(add_previous); OBJ_RELEASE(add_previous);
return; return;
} }
ancestor = zend_read_property_ex(i_get_exception_base(Z_OBJ_P(ancestor)), Z_OBJ_P(ancestor), ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); ancestor = zend_read_property_ex(i_get_exception_base(Z_OBJ_P(ancestor)), Z_OBJ_P(ancestor), ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
ZVAL_DEREF(ancestor);
} }
base_ce = i_get_exception_base(Z_OBJ_P(ex)); base_ce = i_get_exception_base(Z_OBJ_P(ex));
previous = zend_read_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv); previous = zend_read_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
ZVAL_DEREF(previous);
if (Z_TYPE_P(previous) == IS_NULL) { if (Z_TYPE_P(previous) == IS_NULL) {
zend_update_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), &pv); zend_update_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), &pv);
GC_DELREF(add_previous); GC_DELREF(add_previous);
@ -626,6 +629,7 @@ ZEND_METHOD(Exception, getTraceAsString)
RETURN_THROWS(); RETURN_THROWS();
} }
ZVAL_DEREF(trace);
/* Type should be guaranteed by property type. */ /* Type should be guaranteed by property type. */
ZEND_ASSERT(Z_TYPE_P(trace) == IS_ARRAY); ZEND_ASSERT(Z_TYPE_P(trace) == IS_ARRAY);
RETURN_NEW_STR(zend_trace_to_string(Z_ARRVAL_P(trace), /* include_main */ true)); RETURN_NEW_STR(zend_trace_to_string(Z_ARRVAL_P(trace), /* include_main */ true));
@ -639,7 +643,7 @@ ZEND_METHOD(Exception, getPrevious)
ZEND_PARSE_PARAMETERS_NONE(); ZEND_PARSE_PARAMETERS_NONE();
ZVAL_COPY(return_value, GET_PROPERTY_SILENT(ZEND_THIS, ZEND_STR_PREVIOUS)); ZVAL_COPY_DEREF(return_value, GET_PROPERTY_SILENT(ZEND_THIS, ZEND_STR_PREVIOUS));
} /* }}} */ } /* }}} */
/* {{{ Obtain the string representation of the Exception object */ /* {{{ Obtain the string representation of the Exception object */
@ -713,7 +717,8 @@ ZEND_METHOD(Exception, __toString)
Z_PROTECT_RECURSION_P(exception); Z_PROTECT_RECURSION_P(exception);
exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS); exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS);
if (exception && Z_TYPE_P(exception) == IS_OBJECT && Z_IS_RECURSIVE_P(exception)) { ZVAL_DEREF(exception);
if (Z_TYPE_P(exception) == IS_OBJECT && Z_IS_RECURSIVE_P(exception)) {
break; break;
} }
} }
@ -721,13 +726,14 @@ ZEND_METHOD(Exception, __toString)
exception = ZEND_THIS; exception = ZEND_THIS;
/* Reset apply counts */ /* Reset apply counts */
while (exception && Z_TYPE_P(exception) == IS_OBJECT && (base_ce = i_get_exception_base(Z_OBJ_P(exception))) && instanceof_function(Z_OBJCE_P(exception), base_ce)) { while (Z_TYPE_P(exception) == IS_OBJECT && (base_ce = i_get_exception_base(Z_OBJ_P(exception))) && instanceof_function(Z_OBJCE_P(exception), base_ce)) {
if (Z_IS_RECURSIVE_P(exception)) { if (Z_IS_RECURSIVE_P(exception)) {
Z_UNPROTECT_RECURSION_P(exception); Z_UNPROTECT_RECURSION_P(exception);
} else { } else {
break; break;
} }
exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS); exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS);
ZVAL_DEREF(exception);
} }
exception = ZEND_THIS; exception = ZEND_THIS;