[php-src] Issue #24286: Tracing JIT loses the result of a dynamic method call traced with Closure::__invoke (8.5 regression)

From: Date: Tue, 13 Oct 2026 03:02:39 +0000
Subject: [php-src] Issue #24286: Tracing JIT loses the result of a dynamic method call traced with Closure::__invoke (8.5 regression)
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-252982@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/24286 Author: liquidice ### Description > With the tracing JIT, the result of a dynamic method call > $o->{$m}() is lost when the call site was first traced while > calling Closure::__invoke. The caller then reads whatever is left in > the result slot. The following code: ```php <?php class A { function m() { return false; } } function call($o, $m) { return $o->{$m}(); } function every($items, $m) { foreach ($items as $i) { if (!call($i, $m)) return false; } return true; } $c = function () { return false; }; for ($i = 0; $i < 2000; $i++) every([$c], '__invoke'); var_dump(call(new A, 'm')); ``` ```sh php -n -d opcache.enable_cli=1 -d opcache.jit_buffer_size=64M -d opcache.jit=tracing test.php ``` Resulted in this output: ``` UNKNOWN:0 ``` But I expected this output instead: ``` bool(false) ``` > - Wrong on 8.5.0, 8.5.11 and PHP-8.5 @ bbfdd69f, with Ò':¦P<Ä > !þA ’Àopcache.jit=tracing and with 1054. > - Correct with opcache.jit=function, with the JIT off, and on > 8.4.26 and 8.3.35 (tracing). > - Not fixed by #23611 (GH-23572). > - The warm-up through Closure::__invoke is required: warming up > call() with a plain object's method does not reproduce it. The > early return false in every() is > also required. > Valgrind on PHP-8.5 @ bbfdd69f (-g -O2, > USE_ZEND_ALLOC=0 valgrind --smc-check=all --track-origins=yes). > Leaving out the ir_sparse_set_in reports from the JIT compiler, > every remaining error is about the same never-written VM stack memory: it is used in JIT code, > printed by var_dump(), then destroyed: ``` Conditional jump or move depends on uninitialised value(s) at 0x11800ADF: ??? by 0x8C4E9F: zend_execute (zend_vm_execute.h:122008) by 0x9270D5: zend_execute_script (zend.c:1985) Uninitialised value was created by a heap allocation by 0x88CAE8: zend_vm_stack_new_page (zend_execute.h:327) by 0x88CAE8: zend_vm_stack_init (zend_execute.c:195) Conditional jump or move depends on uninitialised value(s) at 0x7668EE: php_var_dump (var.c:130) by 0x7672E0: zif_var_dump (var.c:257) by 0x8C0273: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1360) Uninitialised value was created by a heap allocation by 0x88CAE8: zend_vm_stack_new_page (zend_execute.h:327) by 0x88CAE8: zend_vm_stack_init (zend_execute.c:195) Conditional jump or move depends on uninitialised value(s) at 0x8C02AE: zval_ptr_dtor_nogc (zend_variables.h:35) by 0x8C02AE: zend_vm_stack_free_args (zend_execute.h:405) by 0x8C02AE: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1379) Uninitialised value was created by a heap allocation by 0x88CAE8: zend_vm_stack_new_page (zend_execute.h:327) by 0x88CAE8: zend_vm_stack_init (zend_execute.c:195) ``` > Real-world impact: Laravel's HigherOrderCollectionProxy > closure has this shape. Telescope calls it with Ží²Þþ > 77‹”J¾À˜->every->__invoke($entry) for its filters, and then with > ->partition->isException() when storing entries. On a fresh > laravel/laravel 13.35 + > laravel/telescope 5.25 install (official > php:8.5.11-cli image, default JIT settings apart from > opcache.jit=tracing), an artisan command that logs, uses the cache > and runs queries in a loop crashes with zend_mm_heap corrupted or > SIGSEGV with APP_ENV=production. It crashed in 28 of 32 runs from > 250 iterations up. It does not crash with function JIT, with the JIT off, or on 8.4.26. ### PHP Version ``` PHP 8.5.11 (cli) (built: Oct 6 2026 01:22:31) (NTS) Copyright (c) The PHP Group Built by https://github.com/docker-library/php Zend Engine v4.5.11, Copyright (c) Zend Technologies with Zend OPcache v8.5.11, Copyright (c), by Zend Technologies ``` ### Operating System Debian 13 (official Docker image), x86_64

« previous php.bugs (#252982) next »