]> granicus.if.org Git - php/commitdiff
Skip unnecessary unknown() frames
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 23 Sep 2020 15:06:28 +0000 (17:06 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 24 Sep 2020 08:34:24 +0000 (10:34 +0200)
Noticed this while working on attributes strict_types handling.
We sometimes insert dummy frames internally, but I don't think
these should show up in debug_backtrace output unless they're
needed, either to display an include call or to preserve file/line
information that would otherwise get lost.

Closes GH-6195.

Zend/zend_builtin_functions.c
ext/phar/tests/cache_list/frontcontroller29.phpt
ext/phar/tests/frontcontroller29.phpt

index ac652b3b8a0097f5f58e613c43d75ace83ea87a2..5ec365c9205993af0980df2e92c849508afebd59 100644 (file)
@@ -1781,13 +1781,12 @@ ZEND_FUNCTION(debug_print_backtrace)
                } else {
                        /* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
                        zend_bool build_filename_arg = 1;
+                       uint32_t include_kind = 0;
+                       if (ptr->func && ZEND_USER_CODE(ptr->func->common.type) && ptr->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
+                               include_kind = ptr->opline->extended_value;
+                       }
 
-                       if (!ptr->func || !ZEND_USER_CODE(ptr->func->common.type) || ptr->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
-                               /* can happen when calling eval from a custom sapi */
-                               function_name = "unknown";
-                               build_filename_arg = 0;
-                       } else
-                       switch (ptr->opline->extended_value) {
+                       switch (include_kind) {
                                case ZEND_EVAL:
                                        function_name = "eval";
                                        build_filename_arg = 0;
@@ -1805,8 +1804,11 @@ ZEND_FUNCTION(debug_print_backtrace)
                                        function_name = "require_once";
                                        break;
                                default:
-                                       /* this can actually happen if you use debug_backtrace() in your error_handler and
-                                        * you're in the top-scope */
+                                       /* Skip dummy frame unless it is needed to preserve filename/lineno info. */
+                                       if (!filename) {
+                                               goto skip_frame;
+                                       }
+
                                        function_name = "unknown";
                                        build_filename_arg = 0;
                                        break;
@@ -1857,10 +1859,12 @@ ZEND_FUNCTION(debug_print_backtrace)
                                ZEND_PUTS(")\n");
                        }
                }
+               ++indent;
+
+skip_frame:
                include_filename = filename;
                call = skip;
                ptr = skip->prev_execute_data;
-               ++indent;
        }
 }
 
@@ -2009,13 +2013,12 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
                        /* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
                        zend_bool build_filename_arg = 1;
                        zend_string *pseudo_function_name;
+                       uint32_t include_kind = 0;
+                       if (ptr->func && ZEND_USER_CODE(ptr->func->common.type) && ptr->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
+                               include_kind = ptr->opline->extended_value;
+                       }
 
-                       if (!ptr->func || !ZEND_USER_CODE(ptr->func->common.type) || ptr->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
-                               /* can happen when calling eval from a custom sapi */
-                               pseudo_function_name = ZSTR_KNOWN(ZEND_STR_UNKNOWN);
-                               build_filename_arg = 0;
-                       } else
-                       switch (ptr->opline->extended_value) {
+                       switch (include_kind) {
                                case ZEND_EVAL:
                                        pseudo_function_name = ZSTR_KNOWN(ZEND_STR_EVAL);
                                        build_filename_arg = 0;
@@ -2033,8 +2036,12 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
                                        pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE_ONCE);
                                        break;
                                default:
-                                       /* this can actually happen if you use debug_backtrace() in your error_handler and
-                                        * you're in the top-scope */
+                                       /* Skip dummy frame unless it is needed to preserve filename/lineno info. */
+                                       if (!filename) {
+                                               zval_ptr_dtor(&stack_frame);
+                                               goto skip_frame;
+                                       }
+
                                        pseudo_function_name = ZSTR_KNOWN(ZEND_STR_UNKNOWN);
                                        build_filename_arg = 0;
                                        break;
@@ -2060,8 +2067,8 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
 
                zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &stack_frame);
 
+skip_frame:
                include_filename = filename;
-
                call = skip;
                ptr = skip->prev_execute_data;
        }
index caaf34538e334931a889a24669bec35e15791d3c..a3a9f4e48e89e15d62ca163010042d8cc5fe515d 100644 (file)
@@ -16,7 +16,6 @@ Content-type: text/html; charset=UTF-8
 --EXPECTF--
 Fatal error: Uncaught Error: Call to undefined function oopsie_daisy() in phar://%sfatalerror.phps:1
 Stack trace:
-#0 [internal function]: unknown()
-#1 %s(%d): Phar::webPhar('whatever', 'index.php', '404.php', Array)
-#2 {main}
+#0 %s(%d): Phar::webPhar('whatever', 'index.php', '404.php', Array)
+#1 {main}
   thrown in phar://%sfatalerror.phps on line 1
index 5e18357b6b5d39ac010e0dfd02ca94f3eaf6aee8..2a2ea8c665c019d5728a4b5f3597ab4c28b4b058 100644 (file)
@@ -15,7 +15,6 @@ Content-type: text/html; charset=UTF-8
 --EXPECTF--
 Fatal error: Uncaught Error: Call to undefined function oopsie_daisy() in phar://%sfatalerror.phps:1
 Stack trace:
-#0 [internal function]: unknown()
-#1 %s(%d): Phar::webPhar('whatever', 'index.php', '404.php', Array)
-#2 {main}
+#0 %s(%d): Phar::webPhar('whatever', 'index.php', '404.php', Array)
+#1 {main}
   thrown in phar://%sfatalerror.phps on line 1