From: Sammy Kaye Powers Date: Thu, 24 Sep 2020 19:57:43 +0000 (-0700) Subject: Pass zend_execute_data instead of zend_function to fcall init X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e42abeafeca245950ebc47c7312913e68262d40e;p=php 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 --- diff --git a/Zend/zend_observer.c b/Zend/zend_observer.c index 68cf43ce66..9c2d1cdf51 100644 --- a/Zend/zend_observer.c +++ b/Zend/zend_observer.c @@ -89,9 +89,10 @@ ZEND_API void zend_observer_shutdown(void) { zend_llist_destroy(&zend_observer_error_callbacks); } -static void zend_observer_fcall_install(zend_function *function) { +static void zend_observer_fcall_install(zend_execute_data *execute_data) { zend_llist_element *element; zend_llist *list = &zend_observers_fcall_list; + zend_function *function = execute_data->func; zend_op_array *op_array = &function->op_array; if (fcall_handlers_arena == NULL) { @@ -105,7 +106,7 @@ static void zend_observer_fcall_install(zend_function *function) { for (element = list->head; element; element = element->next) { zend_observer_fcall_init init; memcpy(&init, element->data, sizeof init); - zend_observer_fcall_handlers handlers = init(function); + zend_observer_fcall_handlers handlers = init(execute_data); if (handlers.begin || handlers.end) { zend_llist_add_element(&handlers_list, &handlers); } @@ -150,7 +151,7 @@ static void ZEND_FASTCALL _zend_observe_fcall_begin(zend_execute_data *execute_d fcall_data = ZEND_OBSERVER_DATA(op_array); if (!fcall_data) { - zend_observer_fcall_install((zend_function *)op_array); + zend_observer_fcall_install(execute_data); fcall_data = ZEND_OBSERVER_DATA(op_array); } diff --git a/Zend/zend_observer.h b/Zend/zend_observer.h index 246a3a61be..1d20306a17 100644 --- a/Zend/zend_observer.h +++ b/Zend/zend_observer.h @@ -50,7 +50,7 @@ typedef struct _zend_observer_fcall_handlers { } zend_observer_fcall_handlers; /* If the fn should not be observed then return {NULL, NULL} */ -typedef zend_observer_fcall_handlers (*zend_observer_fcall_init)(zend_function *func); +typedef zend_observer_fcall_handlers (*zend_observer_fcall_init)(zend_execute_data *execute_data); // Call during minit/startup ONLY ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init); 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), ""); +} + +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-- + +--INI-- +zend_test.observer.enabled=1 +zend_test.observer.observe_all=1 +zend_test.observer.show_init_backtrace=1 +--FILE-- +bar($value); + }, [40, 1335]); + } +} + +function gen() +{ + $test = new TestClass(); + yield $test->foo(); +} + +function foo() +{ + return gen()->current(); +} + +var_dump(foo()); +?> +--EXPECTF-- + + + + + + + + + + + + + + + + + + + + + + + + + + + +array(2) { + [0]=> + int(42) + [1]=> + int(1337) +} +