@@ -695,32 +695,43 @@ ZEND_METHOD(Exception, __toString)
695695 zval trace , * exception ;
696696 zend_class_entry * base_ce ;
697697 zend_string * str ;
698- zend_fcall_info fci ;
699698 zval rv , tmp ;
700- zend_string * fname ;
701699
702700 ZEND_PARSE_PARAMETERS_NONE ();
703701
704702 str = ZSTR_EMPTY_ALLOC ();
705703
706704 exception = ZEND_THIS ;
707- fname = ZSTR_INIT_LITERAL ("gettraceasstring" , 0 );
705+ base_ce = i_get_exception_base (Z_OBJ_P (exception ));
706+
707+ /* As getTraceAsString method is final we can grab it once */
708+ zend_function * getTraceAsString = zend_hash_str_find_ptr (& base_ce -> function_table , ZEND_STRL ("gettraceasstring" ));
709+ ZEND_ASSERT (getTraceAsString && "Method getTraceAsString must exist" );
710+
711+
712+ zend_fcall_info fci ;
713+ fci .size = sizeof (fci );
714+ ZVAL_UNDEF (& fci .function_name );
715+ fci .retval = & trace ;
716+ fci .param_count = 0 ;
717+ fci .params = NULL ;
718+ fci .object = NULL ;
719+ fci .named_params = NULL ;
720+
721+ zend_fcall_info_cache fcc ;
722+ fcc .function_handler = getTraceAsString ;
723+ fcc .called_scope = base_ce ;
724+ fcc .closure = NULL ;
708725
709726 while (exception && Z_TYPE_P (exception ) == IS_OBJECT && instanceof_function (Z_OBJCE_P (exception ), zend_ce_throwable )) {
710727 zend_string * prev_str = str ;
711728 zend_string * message = zval_get_string (GET_PROPERTY (exception , ZEND_STR_MESSAGE ));
712729 zend_string * file = zval_get_string (GET_PROPERTY (exception , ZEND_STR_FILE ));
713730 zend_long line = zval_get_long (GET_PROPERTY (exception , ZEND_STR_LINE ));
714731
715- fci .size = sizeof (fci );
716- ZVAL_STR (& fci .function_name , fname );
717- fci .object = Z_OBJ_P (exception );
718- fci .retval = & trace ;
719- fci .param_count = 0 ;
720- fci .params = NULL ;
721- fci .named_params = NULL ;
722-
723- zend_call_function (& fci , NULL );
732+ fcc .object = Z_OBJ_P (exception );
733+ fcc .calling_scope = Z_OBJCE_P (exception );
734+ zend_call_function (& fci , & fcc );
724735
725736 if (Z_TYPE (trace ) != IS_STRING ) {
726737 zval_ptr_dtor (& trace );
@@ -765,11 +776,11 @@ ZEND_METHOD(Exception, __toString)
765776 break ;
766777 }
767778 }
768- zend_string_release_ex (fname , 0 );
769779
770780 exception = ZEND_THIS ;
771781 /* Reset apply counts */
772- 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 )) {
782+ zend_class_entry * previous_base_ce ;
783+ 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 )) {
773784 if (Z_IS_RECURSIVE_P (exception )) {
774785 Z_UNPROTECT_RECURSION_P (exception );
775786 } else {
@@ -779,13 +790,10 @@ ZEND_METHOD(Exception, __toString)
779790 ZVAL_DEREF (exception );
780791 }
781792
782- exception = ZEND_THIS ;
783- base_ce = i_get_exception_base (Z_OBJ_P (exception ));
784-
785793 /* We store the result in the private property string so we can access
786794 * the result in uncaught exception handlers without memleaks. */
787795 ZVAL_STR (& tmp , str );
788- zend_update_property_ex (base_ce , Z_OBJ_P (exception ), ZSTR_KNOWN (ZEND_STR_STRING ), & tmp );
796+ zend_update_property_ex (base_ce , Z_OBJ_P (ZEND_THIS ), ZSTR_KNOWN (ZEND_STR_STRING ), & tmp );
789797
790798 RETURN_STR (str );
791799}
0 commit comments