#
e715dd0a |
| 05-Oct-2024 |
Niels Dossche <7771979+nielsdos@users.noreply.github.com> |
Fixed GH-16233: Observer segfault when calling user function in internal function via trampoline In the test, I have an internal `__call` function for `_ZendTestMagicCallForward` that calls
Fixed GH-16233: Observer segfault when calling user function in internal function via trampoline In the test, I have an internal `__call` function for `_ZendTestMagicCallForward` that calls the global function with name `$name` via `call_user_function`. Note that observer writes the pointer to the previously observed frame in the last temporary of the new call frame (`*prev_observed_frame`). The following happens: First, we call `$test->callee`, this will be handled via a trampoline with T=2 for the two arguments. The call frame is allocated at this point. This call frame is not observed because it has `ZEND_ACC_CALL_VIA_TRAMPOLINE` set. Next we use `ZEND_CALL_TRAMPOLINE` to call the trampoline, this reuses the stack frame allocated earlier with T=2, but this time it is observed. The pointer to the previous frame is written outside of the call frame because `T` is too small (should be 3). We are now in the internal function `_ZendTestMagicCallForward::__call` where we call the global function `callee`. This will push a new call frame which will overlap `*prev_observed_frame`. This value gets overwritten by `zend_init_func_execute_data` when `EX(opline)` is set because `*prev_observed_frame` overlaps with `EX(opline)`. From now on, `*prev_observed_frame` is corrupted. When `zend_observer_fcall_end` is called this will result in reading wrong value `*prev_observed_frame` into `current_observed_frame`. This causes issues in `zend_observer_fcall_end_all` leading to the segfault we observe. Despite function with `ZEND_ACC_CALL_VIA_TRAMPOLINE` not being observed, the reuse of call frames makes problems when `T` is not large enough. To fix this, we make sure to add 1 to `T` if `ZEND_OBSERVER_ENABLED` is true. Closes GH-16252.
show more ...
|