Skip to content

Commit c2115a4

Browse files
committed
Handle references properties of the Exception class
Fixes GH-16188 Closes GH-16196
1 parent a2bdfef commit c2115a4

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

Zend/tests/gh16188.phpt

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
GH-16188 (Assertion failure in Zend/zend_exceptions.c)
3+
--FILE--
4+
<?php
5+
6+
$re = new TypeError();
7+
array_walk($re, function (&$item, $key) use (&$re) {
8+
if ($key === "\x00Error\x00previous") {
9+
$item = new Exception();
10+
}
11+
});
12+
printf("getTraceAsString:\n%s\n\n", $re->getTraceAsString());
13+
printf("getPrevious:\n%s\n\n", get_class($re->getPrevious()));
14+
printf("__toString:\n%s\n\n", $re);
15+
16+
?>
17+
==DONE==
18+
--EXPECTF--
19+
getTraceAsString:
20+
#0 {main}
21+
22+
getPrevious:
23+
Exception
24+
25+
__toString:
26+
Exception in %s:%d
27+
Stack trace:%A
28+
#%d {main}
29+
30+
Next TypeError in %s:%d
31+
Stack trace:%A
32+
#%d {main}
33+
34+
==DONE==

Zend/zend_exceptions.c

+9-3
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,18 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo
115115
ex = &zv;
116116
do {
117117
ancestor = zend_read_property_ex(i_get_exception_base(add_previous), add_previous, ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
118+
ZVAL_DEREF(ancestor);
118119
while (Z_TYPE_P(ancestor) == IS_OBJECT) {
119120
if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) {
120121
OBJ_RELEASE(add_previous);
121122
return;
122123
}
123124
ancestor = zend_read_property_ex(i_get_exception_base(Z_OBJ_P(ancestor)), Z_OBJ_P(ancestor), ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
125+
ZVAL_DEREF(ancestor);
124126
}
125127
base_ce = i_get_exception_base(Z_OBJ_P(ex));
126128
previous = zend_read_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), 1, &rv);
129+
ZVAL_DEREF(previous);
127130
if (Z_TYPE_P(previous) == IS_NULL) {
128131
zend_update_property_ex(base_ce, Z_OBJ_P(ex), ZSTR_KNOWN(ZEND_STR_PREVIOUS), &pv);
129132
GC_DELREF(add_previous);
@@ -630,6 +633,7 @@ ZEND_METHOD(Exception, getTraceAsString)
630633
RETURN_THROWS();
631634
}
632635

636+
ZVAL_DEREF(trace);
633637
/* Type should be guaranteed by property type. */
634638
ZEND_ASSERT(Z_TYPE_P(trace) == IS_ARRAY);
635639
RETURN_NEW_STR(zend_trace_to_string(Z_ARRVAL_P(trace), /* include_main */ true));
@@ -643,7 +647,7 @@ ZEND_METHOD(Exception, getPrevious)
643647

644648
ZEND_PARSE_PARAMETERS_NONE();
645649

646-
ZVAL_COPY(return_value, GET_PROPERTY_SILENT(ZEND_THIS, ZEND_STR_PREVIOUS));
650+
ZVAL_COPY_DEREF(return_value, GET_PROPERTY_SILENT(ZEND_THIS, ZEND_STR_PREVIOUS));
647651
} /* }}} */
648652

649653
/* {{{ Obtain the string representation of the Exception object */
@@ -723,21 +727,23 @@ ZEND_METHOD(Exception, __toString)
723727

724728
Z_PROTECT_RECURSION_P(exception);
725729
exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS);
726-
if (exception && Z_TYPE_P(exception) == IS_OBJECT && Z_IS_RECURSIVE_P(exception)) {
730+
ZVAL_DEREF(exception);
731+
if (Z_TYPE_P(exception) == IS_OBJECT && Z_IS_RECURSIVE_P(exception)) {
727732
break;
728733
}
729734
}
730735
zend_string_release_ex(fname, 0);
731736

732737
exception = ZEND_THIS;
733738
/* Reset apply counts */
734-
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)) {
739+
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)) {
735740
if (Z_IS_RECURSIVE_P(exception)) {
736741
Z_UNPROTECT_RECURSION_P(exception);
737742
} else {
738743
break;
739744
}
740745
exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS);
746+
ZVAL_DEREF(exception);
741747
}
742748

743749
exception = ZEND_THIS;

0 commit comments

Comments
 (0)