From cd64a0cc9c3340912c1514b121c6b83e05455cbd Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Thu, 3 Oct 2024 13:18:16 +0200 Subject: [PATCH 1/2] Handle references after fetching Exception properties --- Zend/tests/gh16188.phpt | 34 ++++++++++++++++++++++++++++++++++ Zend/zend_exceptions.c | 16 ++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 Zend/tests/gh16188.phpt diff --git a/Zend/tests/gh16188.phpt b/Zend/tests/gh16188.phpt new file mode 100644 index 0000000000000..4516f7cade90b --- /dev/null +++ b/Zend/tests/gh16188.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-16188 (Assertion failure in Zend/zend_exceptions.c) +--FILE-- +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== diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 8ad603e51e71c..50a2348a7a4ef 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -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)); @@ -639,11 +643,13 @@ ZEND_METHOD(Exception, getTraceAsString) /* {{{ Return previous Throwable or NULL. */ ZEND_METHOD(Exception, getPrevious) { - zval rv; + zval *prop, rv; ZEND_PARSE_PARAMETERS_NONE(); - ZVAL_COPY(return_value, GET_PROPERTY_SILENT(ZEND_THIS, ZEND_STR_PREVIOUS)); + prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_PREVIOUS); + ZVAL_DEREF(prop); + ZVAL_COPY(return_value, prop); } /* }}} */ /* {{{ Obtain the string representation of the Exception object */ @@ -723,7 +729,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 +738,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; From 87162f85c82b7b6870d2d13bf9e8a0270e9b843d Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Fri, 4 Oct 2024 13:48:15 +0200 Subject: [PATCH 2/2] Review --- Zend/zend_exceptions.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 50a2348a7a4ef..d2547ced6f7f5 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -643,13 +643,11 @@ ZEND_METHOD(Exception, getTraceAsString) /* {{{ Return previous Throwable or NULL. */ ZEND_METHOD(Exception, getPrevious) { - zval *prop, rv; + zval rv; ZEND_PARSE_PARAMETERS_NONE(); - prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_PREVIOUS); - ZVAL_DEREF(prop); - ZVAL_COPY(return_value, prop); + ZVAL_COPY_DEREF(return_value, GET_PROPERTY_SILENT(ZEND_THIS, ZEND_STR_PREVIOUS)); } /* }}} */ /* {{{ Obtain the string representation of the Exception object */