@@ -542,6 +542,31 @@ static void _build_trace_args(zval *arg, smart_str *str) /* {{{ */
542542}
543543/* }}} */
544544
545+ static void _build_trace_args_list (zval * tmp , smart_str * str ) /* {{{ */
546+ {
547+ if (EXPECTED (Z_TYPE_P (tmp ) == IS_ARRAY )) {
548+ size_t last_len = ZSTR_LEN (str -> s );
549+ zend_string * name ;
550+ zval * arg ;
551+
552+ ZEND_HASH_FOREACH_STR_KEY_VAL (Z_ARRVAL_P (tmp ), name , arg ) {
553+ if (name ) {
554+ smart_str_append (str , name );
555+ smart_str_appends (str , ": " );
556+ }
557+ _build_trace_args (arg , str );
558+ } ZEND_HASH_FOREACH_END ();
559+
560+ if (last_len != ZSTR_LEN (str -> s )) {
561+ ZSTR_LEN (str -> s ) -= 2 ; /* remove last ', ' */
562+ }
563+ } else {
564+ /* only happens w/ reflection abuse (Zend/tests/bug63762.phpt) */
565+ zend_error (E_WARNING , "args element is not an array" );
566+ }
567+ }
568+ /* }}} */
569+
545570static void _build_trace_string (smart_str * str , const HashTable * ht , uint32_t num ) /* {{{ */
546571{
547572 zval * file , * tmp ;
@@ -588,30 +613,49 @@ static void _build_trace_string(smart_str *str, const HashTable *ht, uint32_t nu
588613 smart_str_appendc (str , '(' );
589614 tmp = zend_hash_find_known_hash (ht , ZSTR_KNOWN (ZEND_STR_ARGS ));
590615 if (tmp ) {
591- if (EXPECTED (Z_TYPE_P (tmp ) == IS_ARRAY )) {
592- size_t last_len = ZSTR_LEN (str -> s );
593- zend_string * name ;
594- zval * arg ;
595-
596- ZEND_HASH_FOREACH_STR_KEY_VAL (Z_ARRVAL_P (tmp ), name , arg ) {
597- if (name ) {
598- smart_str_append (str , name );
599- smart_str_appends (str , ": " );
600- }
601- _build_trace_args (arg , str );
602- } ZEND_HASH_FOREACH_END ();
603-
604- if (last_len != ZSTR_LEN (str -> s )) {
605- ZSTR_LEN (str -> s ) -= 2 ; /* remove last ', ' */
606- }
607- } else {
608- zend_error (E_WARNING , "args element is not an array" );
609- }
616+ _build_trace_args_list (tmp , str );
610617 }
611618 smart_str_appends (str , ")\n" );
612619}
613620/* }}} */
614621
622+ /* {{{ Gets the function arguments printed as a string from a backtrace frame. */
623+ ZEND_API zend_string * zend_trace_function_args_to_string (const HashTable * frame ) {
624+ zval * tmp ;
625+ smart_str str = {0 };
626+ /* init because ASan will complain */
627+ smart_str_appends (& str , "" );
628+
629+ tmp = zend_hash_find_known_hash (frame , ZSTR_KNOWN (ZEND_STR_ARGS ));
630+ if (tmp ) {
631+ _build_trace_args_list (tmp , & str );
632+ }
633+
634+ smart_str_0 (& str );
635+ return str .s ? str .s : ZSTR_EMPTY_ALLOC ();
636+ }
637+ /* }}} */
638+
639+ /* {{{ Gets the currently executing function's arguments as a string. Used by php_verror. */
640+ ZEND_API zend_string * zend_trace_current_function_args_string (void ) {
641+ zend_string * dynamic_params = NULL ;
642+ /* get a backtrace to snarf function args */
643+ zval backtrace , * first_frame ;
644+ zend_fetch_debug_backtrace (& backtrace , /* skip_last */ 0 , /* options */ 0 , /* limit */ 1 );
645+ /* can fail esp if low memory condition */
646+ if (Z_TYPE (backtrace ) != IS_ARRAY ) {
647+ return NULL ; /* don't need to free */
648+ }
649+ first_frame = zend_hash_index_find (Z_ARRVAL (backtrace ), 0 );
650+ if (first_frame ) {
651+ dynamic_params = zend_trace_function_args_to_string (Z_ARRVAL_P (first_frame ));
652+ }
653+ zval_ptr_dtor (& backtrace );
654+ /* free the string after we use it */
655+ return dynamic_params ;
656+ }
657+ /* }}} */
658+
615659ZEND_API zend_string * zend_trace_to_string (const HashTable * trace , bool include_main ) {
616660 zend_ulong index ;
617661 zval * frame ;
0 commit comments