1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Zend: Exception::__toString() no need to allocate the method name

We can create the FCI/FCC pair ourself outside of the loop as the method getTraceAsString is final

Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
This commit is contained in:
Gina Peter Banyard
2025-07-03 17:11:14 +01:00
parent c9e91bfbab
commit a95a81000d

View File

@@ -695,16 +695,33 @@ ZEND_METHOD(Exception, __toString)
zval trace, *exception;
zend_class_entry *base_ce;
zend_string *str;
zend_fcall_info fci;
zval rv, tmp;
zend_string *fname;
ZEND_PARSE_PARAMETERS_NONE();
str = ZSTR_EMPTY_ALLOC();
exception = ZEND_THIS;
fname = ZSTR_INIT_LITERAL("gettraceasstring", 0);
base_ce = i_get_exception_base(Z_OBJ_P(exception));
/* As getTraceAsString method is final we can grab it once */
zend_function *getTraceAsString = zend_hash_str_find_ptr(&base_ce->function_table, ZEND_STRL("gettraceasstring"));
ZEND_ASSERT(getTraceAsString && "Method getTraceAsString must exist");
zend_fcall_info fci;
fci.size = sizeof(fci);
ZVAL_UNDEF(&fci.function_name);
fci.retval = &trace;
fci.param_count = 0;
fci.params = NULL;
fci.object = NULL;
fci.named_params = NULL;
zend_fcall_info_cache fcc;
fcc.function_handler = getTraceAsString;
fcc.called_scope = base_ce;
fcc.closure = NULL;
while (exception && Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), zend_ce_throwable)) {
zend_string *prev_str = str;
@@ -712,15 +729,9 @@ ZEND_METHOD(Exception, __toString)
zend_string *file = zval_get_string(GET_PROPERTY(exception, ZEND_STR_FILE));
zend_long line = zval_get_long(GET_PROPERTY(exception, ZEND_STR_LINE));
fci.size = sizeof(fci);
ZVAL_STR(&fci.function_name, fname);
fci.object = Z_OBJ_P(exception);
fci.retval = &trace;
fci.param_count = 0;
fci.params = NULL;
fci.named_params = NULL;
zend_call_function(&fci, NULL);
fcc.object = Z_OBJ_P(exception);
fcc.calling_scope = Z_OBJCE_P(exception);
zend_call_function(&fci, &fcc);
if (Z_TYPE(trace) != IS_STRING) {
zval_ptr_dtor(&trace);
@@ -765,11 +776,11 @@ ZEND_METHOD(Exception, __toString)
break;
}
}
zend_string_release_ex(fname, 0);
exception = ZEND_THIS;
/* Reset apply counts */
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)) {
zend_class_entry *previous_base_ce;
while (Z_TYPE_P(exception) == IS_OBJECT && (previous_base_ce = i_get_exception_base(Z_OBJ_P(exception))) && instanceof_function(Z_OBJCE_P(exception), previous_base_ce)) {
if (Z_IS_RECURSIVE_P(exception)) {
Z_UNPROTECT_RECURSION_P(exception);
} else {
@@ -779,13 +790,10 @@ ZEND_METHOD(Exception, __toString)
ZVAL_DEREF(exception);
}
exception = ZEND_THIS;
base_ce = i_get_exception_base(Z_OBJ_P(exception));
/* We store the result in the private property string so we can access
* the result in uncaught exception handlers without memleaks. */
ZVAL_STR(&tmp, str);
zend_update_property_ex(base_ce, Z_OBJ_P(exception), ZSTR_KNOWN(ZEND_STR_STRING), &tmp);
zend_update_property_ex(base_ce, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_STRING), &tmp);
RETURN_STR(str);
}