Skip to content

[Observer] Pass zend_execute_data instead of zend_function to fcall init #6209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Zend/zend_observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_observer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
30 changes: 28 additions & 2 deletions ext/zend_test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)) {
Expand Down
106 changes: 106 additions & 0 deletions ext/zend_test/tests/observer_backtrace_01.phpt
Original file line number Diff line number Diff line change
@@ -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'>