summaryrefslogtreecommitdiff
path: root/ext/zend_test
diff options
context:
space:
mode:
authorSammy Kaye Powers <sammyk@php.net>2020-09-24 12:57:43 -0700
committerSammy Kaye Powers <sammyk@php.net>2020-09-25 11:46:15 -0700
commite42abeafeca245950ebc47c7312913e68262d40e (patch)
treebf62186a7ea10351ed31063a3bd2455fa7b978b4 /ext/zend_test
parenta91cb2f48c275751df1ab0a3f9e9a28c200add77 (diff)
downloadphp-git-e42abeafeca245950ebc47c7312913e68262d40e.tar.gz
Pass zend_execute_data instead of zend_function to fcall init
The motivation for this change is to prevent extensions from having to check executor globals for the current execute_data during function call init. A previous implementation of the observer API initialized the function call from runtime cache initialization before execute_data was allocated which is why zend_function was passed in. But now that the observer API is implemented via opcode specialization, it makes sense to pass in the execute_data. This also keeps the API a bit more consistent for existing extensions that already hook zend_execute_ex. Closes GH-6209
Diffstat (limited to 'ext/zend_test')
-rw-r--r--ext/zend_test/test.c30
-rw-r--r--ext/zend_test/tests/observer_backtrace_01.phpt106
2 files changed, 134 insertions, 2 deletions
diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
index 4ca98a3c08..92b8e4cf6a 100644
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@ -36,6 +36,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
int observer_observe_functions;
int observer_show_return_type;
int observer_show_return_value;
+ int observer_show_init_backtrace;
int observer_nesting_depth;
ZEND_END_MODULE_GLOBALS(zend_test)
@@ -315,9 +316,10 @@ PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN("zend_test.observer.observe_functions", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_observe_functions, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_type", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_type, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_value", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_value, zend_zend_test_globals, zend_test_globals)
+ STD_PHP_INI_BOOLEAN("zend_test.observer.show_init_backtrace", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_init_backtrace, zend_zend_test_globals, zend_test_globals)
PHP_INI_END()
-static zend_observer_fcall_handlers observer_fcall_init(zend_function *fbc);
+static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execute_data);
PHP_MINIT_FUNCTION(zend_test)
{
@@ -498,10 +500,34 @@ static void observer_show_init(zend_function *fbc)
}
}
-static zend_observer_fcall_handlers observer_fcall_init(zend_function *fbc)
+static void observer_show_init_backtrace(zend_execute_data *execute_data)
{
+ zend_execute_data *ex = execute_data;
+ php_printf("%*s<!--\n", 2 * ZT_G(observer_nesting_depth), "");
+ do {
+ zend_function *fbc = ex->func;
+ int indent = 2 * ZT_G(observer_nesting_depth) + 4;
+ if (fbc->common.function_name) {
+ if (fbc->common.scope) {
+ php_printf("%*s%s::%s()\n", indent, "", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
+ } else {
+ php_printf("%*s%s()\n", indent, "", ZSTR_VAL(fbc->common.function_name));
+ }
+ } else {
+ php_printf("%*s{main} %s\n", indent, "", ZSTR_VAL(fbc->op_array.filename));
+ }
+ } while ((ex = ex->prev_execute_data) != NULL);
+ php_printf("%*s-->\n", 2 * ZT_G(observer_nesting_depth), "");
+}
+
+static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execute_data)
+{
+ zend_function *fbc = execute_data->func;
if (ZT_G(observer_show_output)) {
observer_show_init(fbc);
+ if (ZT_G(observer_show_init_backtrace)) {
+ observer_show_init_backtrace(execute_data);
+ }
}
if (ZT_G(observer_observe_all)) {
diff --git a/ext/zend_test/tests/observer_backtrace_01.phpt b/ext/zend_test/tests/observer_backtrace_01.phpt
new file mode 100644
index 0000000000..7aa47c2ef2
--- /dev/null
+++ b/ext/zend_test/tests/observer_backtrace_01.phpt
@@ -0,0 +1,106 @@
+--TEST--
+Observer: Show backtrace on init
+--SKIPIF--
+<?php if (!extension_loaded('zend-test')) die('skip: zend-test extension required'); ?>
+--INI--
+zend_test.observer.enabled=1
+zend_test.observer.observe_all=1
+zend_test.observer.show_init_backtrace=1
+--FILE--
+<?php
+class TestClass
+{
+ private function bar($number)
+ {
+ return $number + 2;
+ }
+
+ public function foo()
+ {
+ return array_map(function ($value) {
+ return $this->bar($value);
+ }, [40, 1335]);
+ }
+}
+
+function gen()
+{
+ $test = new TestClass();
+ yield $test->foo();
+}
+
+function foo()
+{
+ return gen()->current();
+}
+
+var_dump(foo());
+?>
+--EXPECTF--
+<!-- init '%s/observer_backtrace_%d.php' -->
+<!--
+ {main} %s/observer_backtrace_%d.php
+-->
+<file '%s/observer_backtrace_%d.php'>
+ <!-- init foo() -->
+ <!--
+ foo()
+ {main} %s/observer_backtrace_%d.php
+ -->
+ <foo>
+ <!-- init gen() -->
+ <!--
+ gen()
+ Generator::current()
+ foo()
+ {main} %s/observer_backtrace_%d.php
+ -->
+ <gen>
+ <!-- init TestClass::foo() -->
+ <!--
+ TestClass::foo()
+ gen()
+ Generator::current()
+ foo()
+ {main} %s/observer_backtrace_%d.php
+ -->
+ <TestClass::foo>
+ <!-- init TestClass::{closure}() -->
+ <!--
+ TestClass::{closure}()
+ array_map()
+ TestClass::foo()
+ gen()
+ Generator::current()
+ foo()
+ {main} %s/observer_backtrace_%d.php
+ -->
+ <TestClass::{closure}>
+ <!-- init TestClass::bar() -->
+ <!--
+ TestClass::bar()
+ TestClass::{closure}()
+ array_map()
+ TestClass::foo()
+ gen()
+ Generator::current()
+ foo()
+ {main} %s/observer_backtrace_%d.php
+ -->
+ <TestClass::bar>
+ </TestClass::bar>
+ </TestClass::{closure}>
+ <TestClass::{closure}>
+ <TestClass::bar>
+ </TestClass::bar>
+ </TestClass::{closure}>
+ </TestClass::foo>
+ </gen>
+ </foo>
+array(2) {
+ [0]=>
+ int(42)
+ [1]=>
+ int(1337)
+}
+</file '%s/observer_backtrace_%d.php'>