Skip to content

Add next handler parameter to zend_observer_remove_begin/end_handler #13807

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

Merged
merged 1 commit into from
Apr 7, 2024
Merged
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
4 changes: 4 additions & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ PHP 8.4 INTERNALS UPGRADE NOTES
void(*)(void *, size_t) to
void(*)(void *, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)

* zend_observer_remove_begin_handler() and zend_observer_remove_end_handler()
got each a new parameter returning an observer which must be called, if the
removal happened during observer execution.


========================
2. Build system changes
Expand Down
17 changes: 12 additions & 5 deletions Zend/zend_observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,19 +147,26 @@ static void zend_observer_fcall_install(zend_execute_data *execute_data)
}
}

static bool zend_observer_remove_handler(void **first_handler, void *old_handler) {
/* We need to provide the ability to retrieve the handler which will move onto the position the current handler was.
* The fundamental problem is that, if a handler is removed while it's being executed, it will move handlers around:
* the previous next handler is now at the place where the current handler was.
* Hence, the next handler executed will be the one after the next handler.
* Callees must thus invoke the next handler themselves, with the same arguments they were passed. */
static bool zend_observer_remove_handler(void **first_handler, void *old_handler, void **next_handler) {
size_t registered_observers = zend_observers_fcall_list.count;

void **last_handler = first_handler + registered_observers - 1;
for (void **cur_handler = first_handler; cur_handler <= last_handler; ++cur_handler) {
if (*cur_handler == old_handler) {
if (registered_observers == 1 || (cur_handler == first_handler && cur_handler[1] == NULL)) {
*cur_handler = ZEND_OBSERVER_NOT_OBSERVED;
*next_handler = NULL;
} else {
if (cur_handler != last_handler) {
memmove(cur_handler, cur_handler + 1, sizeof(cur_handler) * (last_handler - cur_handler));
}
*last_handler = NULL;
*next_handler = *cur_handler;
}
return true;
}
Expand All @@ -184,8 +191,8 @@ ZEND_API void zend_observer_add_begin_handler(zend_function *function, zend_obse
}
}

ZEND_API bool zend_observer_remove_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin) {
return zend_observer_remove_handler((void **)&ZEND_OBSERVER_DATA(function), begin);
ZEND_API bool zend_observer_remove_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin, zend_observer_fcall_begin_handler *next) {
return zend_observer_remove_handler((void **)&ZEND_OBSERVER_DATA(function), begin, (void **)next);
}

ZEND_API void zend_observer_add_end_handler(zend_function *function, zend_observer_fcall_end_handler end) {
Expand All @@ -200,9 +207,9 @@ ZEND_API void zend_observer_add_end_handler(zend_function *function, zend_observ
*end_handler = end;
}

ZEND_API bool zend_observer_remove_end_handler(zend_function *function, zend_observer_fcall_end_handler end) {
ZEND_API bool zend_observer_remove_end_handler(zend_function *function, zend_observer_fcall_end_handler end, zend_observer_fcall_end_handler *next) {
size_t registered_observers = zend_observers_fcall_list.count;
return zend_observer_remove_handler((void **)&ZEND_OBSERVER_DATA(function) + registered_observers, end);
return zend_observer_remove_handler((void **)&ZEND_OBSERVER_DATA(function) + registered_observers, end, (void **)next);
}

static inline zend_execute_data **prev_observed_frame(zend_execute_data *execute_data) {
Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_observer.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init);
// Call during runtime, but only if you have used zend_observer_fcall_register.
// You must not have more than one begin and one end handler active at the same time. Remove the old one first, if there is an existing one.
ZEND_API void zend_observer_add_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin);
ZEND_API bool zend_observer_remove_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin);
ZEND_API bool zend_observer_remove_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin, zend_observer_fcall_begin_handler *next);
ZEND_API void zend_observer_add_end_handler(zend_function *function, zend_observer_fcall_end_handler end);
ZEND_API bool zend_observer_remove_end_handler(zend_function *function, zend_observer_fcall_end_handler end);
ZEND_API bool zend_observer_remove_end_handler(zend_function *function, zend_observer_fcall_end_handler end, zend_observer_fcall_end_handler *next);

ZEND_API void zend_observer_startup(void); // Called by engine before MINITs
ZEND_API void zend_observer_post_startup(void); // Called by engine after MINITs
Expand Down
5 changes: 3 additions & 2 deletions ext/zend_test/observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,9 @@ static ZEND_INI_MH(zend_test_observer_OnUpdateCommaList)
if (stage != PHP_INI_STAGE_STARTUP && stage != PHP_INI_STAGE_ACTIVATE && stage != PHP_INI_STAGE_DEACTIVATE && stage != PHP_INI_STAGE_SHUTDOWN) {
ZEND_HASH_FOREACH_STR_KEY(*p, funcname) {
if ((func = zend_hash_find_ptr(EG(function_table), funcname))) {
zend_observer_remove_begin_handler(func, observer_begin);
zend_observer_remove_end_handler(func, observer_end);
void *old_handler;
zend_observer_remove_begin_handler(func, observer_begin, (zend_observer_fcall_begin_handler *)&old_handler);
zend_observer_remove_end_handler(func, observer_end, (zend_observer_fcall_end_handler *)&old_handler);
}
} ZEND_HASH_FOREACH_END();
}
Expand Down