Handle references properties of the Exception class

Fixes GH-16188
Closes GH-16196
This commit is contained in:
Arnaud Le Blanc 2024-10-03 13:18:16 +02:00
parent a2bdfeff4f
commit c2115a43e3
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

@ -115,15 +115,18 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo
ex = &zv;
do {
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) {
if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) {
OBJ_RELEASE(add_previous);
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);
ZVAL_DEREF(ancestor);
}
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);
ZVAL_DEREF(previous);
if (Z_TYPE_P(previous) == IS_NULL) {
zend_update_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), &pv);
GC_DELREF(add_previous);
@ -630,6 +633,7 @@ ZEND_METHOD(Exception, getTraceAsString)
RETURN_THROWS();
}
ZVAL_DEREF(trace);
/* Type should be guaranteed by property type. */
ZEND_ASSERT(Z_TYPE_P(trace) == IS_ARRAY);
RETURN_NEW_STR(zend_trace_to_string(Z_ARRVAL_P(trace), /* include_main */ true));
@ -643,7 +647,7 @@ ZEND_METHOD(Exception, getPrevious)
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 */
@ -723,7 +727,8 @@ ZEND_METHOD(Exception, __toString)
Z_PROTECT_RECURSION_P(exception);
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;
}
}
@ -731,13 +736,14 @@ ZEND_METHOD(Exception, __toString)
exception = ZEND_THIS;
/* 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)) {
Z_UNPROTECT_RECURSION_P(exception);
} else {
break;
}
exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS);
ZVAL_DEREF(exception);
}
exception = ZEND_THIS;