Description
Description
When observer fcall handlers are used to observer PHP function calls and tracing JIT is enabled, then execute_data->opline
pointers in the fcall handler may become unreliable (not NULL and not valid either) causing the PHP process to crash when these pointers are used.
A common scenario would be accessing execute_data->opline->lineno
to get the line number. The following simple observer handler should print out the line number for every called user function:
static void observer_begin(zend_execute_data *ex)
{
if (ZEND_USER_CODE(ex->func->type) && ex->opline) {
printf("%u\n", ex->opline->lineno);
}
}
The actual result is that the PHP process crashes due to the execute_data->opline
pointer being not NULL and not a valid pointer either:
Process 46323 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x19)
frame #0: 0x000000010146be44 php-observer.so`observer_begin(ex=0x0000000100c17150) at php_observer.c:58:36
55 static void observer_begin(zend_execute_data *ex)
56 {
57 if (ZEND_USER_CODE(ex->func->type) && ex->opline) {
-> 58 printf("%u\n", ex->opline->lineno);
59 }
60 }
> p ex->opline
(const zend_op *) 0x0000000000000001
Backtrace of the crashing PHP process:
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x19)
* frame #0: 0x000000010146be44 php-observer.so`observer_begin(ex=0x0000000100c17150) at php_observer.c:58:36
frame #1: 0x0000000100734340 php`_zend_observe_fcall_begin(execute_data=0x0000000100c17150) at zend_observer.c:244:3
frame #2: 0x00000001007343d4 php`zend_observer_fcall_begin(execute_data=0x0000000100c17150) at zend_observer.c:257:3
frame #3: 0x0000000138008638
frame #4: 0x00000001005aef34 php`zend_call_function(fci=0x000000016fdfdc68, fci_cache=0x000000016fdfdc40) at zend_execute_API.c:957:3
frame #5: 0x0000000100350d18 php`zif_call_user_func_array(execute_data=0x0000000100c16500, return_value=0x0000000100c164c0) at basic_functions.c:1514:6
frame #6: 0x0000000100698880 php`ZEND_DO_FCALL_BY_NAME_SPEC_OBSERVER_HANDLER(execute_data=0x0000000100c16450) at zend_vm_execute.h:1759:3
frame #7: 0x00000001006155f4 php`execute_ex(ex=0x0000000100c16020) at zend_vm_execute.h:57007:7
frame #8: 0x00000001006159f0 php`zend_execute(op_array=0x0000000100c9b000, return_value=0x0000000000000000) at zend_vm_execute.h:61604:2
frame #9: 0x00000001005cfac0 php`zend_execute_scripts(type=8, retval=0x0000000000000000, file_count=3) at zend.c:1883:4
frame #10: 0x00000001004fc61c php`php_execute_script(primary_file=0x000000016fdfe570) at main.c:2507:13
frame #11: 0x00000001007d1440 php`php_cli_server_dispatch_script(server=0x00000001009ab9e8, client=0x0000000114f45990) at php_cli_server.c:2122:3
frame #12: 0x00000001007cee20 php`php_cli_server_dispatch(server=0x00000001009ab9e8, client=0x0000000114f45990) at php_cli_server.c:2312:18
frame #13: 0x00000001007cd8d4 php`php_cli_server_recv_event_read_request(server=0x00000001009ab9e8, client=0x0000000114f45990) at php_cli_server.c:2641:11
frame #14: 0x00000001007cdf84 php`php_cli_server_do_event_for_each_fd_callback(_params=0x000000016fdfe870, fd=5, event=1) at php_cli_server.c:2726:5
frame #15: 0x00000001007cdbe8 php`php_cli_server_poller_iter_on_active(poller=0x00000001009ab9ec, opaque=0x000000016fdfe870, callback=(php`php_cli_server_do_event_for_each_fd_callback at php_cli_server.c:2688)) at php_cli_server.c:932:20
frame #16: 0x00000001007cd710 php`php_cli_server_do_event_for_each_fd(server=0x00000001009ab9e8, rhandler=(php`php_cli_server_recv_event_read_request at php_cli_server.c:2620), whandler=(php`php_cli_server_send_event at php_cli_server.c:2652)) at php_cli_server.c:2746:17
frame #17: 0x00000001007ca94c php`php_cli_server_do_event_loop(server=0x00000001009ab9e8) at php_cli_server.c:2758:4
frame #18: 0x00000001007ca408 php`do_cli_server(argc=3, argv=0x00006000033b3040) at php_cli_server.c:2890:17
frame #19: 0x00000001007c18b4 php`main(argc=3, argv=0x00006000033b3040) at php_cli.c:1343:18
frame #20: 0x000000018d6360e0 dyld`start + 2360
I haven't been able to isolate a simple PHP script that would trigger this issue. The crash above was observed when running an application using Yii framework. @dstogov confirmed the bug and has a zend_test
patch that reproduces the issue by running bench.php
.
PHP Version
PHP 8.3.4
Operating System
macOS 14.4