-
Notifications
You must be signed in to change notification settings - Fork 8k
Open
Description
Description
The following code:
<?php
/**
* JIT bus error reproduction — PHP 8.5.2, arm64, opcache.jit=tracing
*
* Run:
* php -dopcache.enable_cli=1 -dopcache.jit=tracing -dopcache.jit_buffer_size=64M jit-repro.php
*
* Requires: azjezz/psl 5.1.0
*
* Crashes ~40% of the time on arm64 with JIT tracing mode.
* The JIT miscompiles ZEND_FETCH_OBJ_FUNC_ARG on a property hook,
* returning `call_leave_op` (a data-segment pointer in __DATA_CONST)
* as the next opcode handler. ARM64 W^X policy prevents executing
* data pages → EXC_BAD_ACCESS (code=2).
*/
declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';
use Psl\Async;
use Psl\IO;
use Psl\TLS;
enum Kind: int { case A = 1; }
final class Rec {
public Kind $kind { get => Kind::A; }
public function __construct(public readonly string $name) {}
}
const Q = "\x00\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\x01\x00\x01";
function dnsq(string $srv, string $name): array {
$c = TLS\connect($srv, 853);
$c->writeAll(pack('n', strlen(Q)) . Q);
$c->readAll(unpack('n', $c->readAll(2))[1]);
$c->close();
return [new Rec($name)];
}
function race(string $n): array {
return Async\first(array_map(fn($srv) => Async\run(fn() => dnsq($srv, $n)), ['1.1.1.1', '8.8.8.8']));
}
$tasks = [];
foreach (['a.com', 'b.com', 'c.com'] as $d) {
$tasks[$d] = Async\run(static fn() => Async\concurrently([
0 => fn() => race($d), 1 => fn() => race($d), 2 => fn() => race($d),
]));
}
foreach (Async\all($tasks) as $responses) {
foreach ($responses[0] as $r) { IO\write_line('[%s]: %s', $r->name, $r->kind->name); }
foreach ($responses[1] as $r) { IO\write_line('[%s]: %s', $r->name, $r->kind->name); }
foreach ($responses[2] as $r) { IO\write_line('[%s]: %s', $r->name, $r->kind->name); }
}
echo "OK\n";Resulted in this output:
[a.com]: A
[a.com]: A
[a.com]: A
[b.com]: A
[b.com]: A
[b.com]: A
[c.com]: A
[1] 8610 bus error php -dopcache.enable_cli=1 -dopcache.jit=tracing -dopcache.jit_buffer_size=64
But I expected this output instead:
[a.com]: A
[a.com]: A
[a.com]: A
[b.com]: A
[b.com]: A
[b.com]: A
[c.com]: A
[c.com]: A
[c.com]: A
OK
Crash: EXC_BAD_ACCESS (code=2, address=0x101409048) at call_leave_op
Crash site: Line 36 - IO\write_line('[%s]: %s', $r->name, $r->kind->name) where $r->kind is a property hook (public Kind $kind { get => Kind::A; })
Stack trace:
➜ leaf git:(main) ✗ lldb php examples/dns/jit-repro.php
(lldb) target create "php"
Current executable set to '/Users/azjezz/.phpbrew/php/8.5.2/bin/php' (arm64).
(lldb) settings set -- target.run-args "examples/dns/jit-repro.php"
(lldb) run
Process 14499 launched: '/Users/azjezz/.phpbrew/php/8.5.2/bin/php' (arm64)
[a.com]: A
[a.com]: A
[a.com]: A
[b.com]: A
[b.com]: A
[b.com]: A
[c.com]: A
[c.com]: A
[c.com]: A
OK
Process 14499 exited with status = 0 (0x00000000)
(lldb) run
Process 14550 launched: '/Users/azjezz/.phpbrew/php/8.5.2/bin/php' (arm64)
[a.com]: A
[a.com]: A
[a.com]: A
[b.com]: A
[b.com]: A
[b.com]: A
[c.com]: A
[c.com]: A
Process 14550 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x101409048)
frame #0: 0x0000000101409048 php`call_leave_op
php`call_leave_op:
-> 0x101409048 <+0>: <unknown>
0x10140904c <+4>: udf #0x1
0x101409050 <+8>: udf #0x0
0x101409054 <+12>: udf #0x0
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x101409048)
* frame #0: 0x0000000101409048 php`call_leave_op
frame #1: 0x000000010061cf44 php`execute_ex(ex=<unavailable>) at zend_vm_execute.h:116172:12 [opt]
frame #2: 0x000000010062f32c php`zend_execute.cold.1 at zend_vm_execute.h:121884:2 [opt]
frame #3: 0x00000001004eab18 php`zend_execute(op_array=<unavailable>, return_value=<unavailable>) at zend_vm_execute.h:121867:48 [opt]
frame #4: 0x00000001005c5830 php`zend_execute_script(type=8, retval=0x0000000000000000, file_handle=0x000000016fdfe140) at zend.c:1977:3 [opt]
frame #5: 0x0000000100437d50 php`php_execute_script_ex(primary_file=0x000000016fdfe140, retval=0x0000000000000000) at main.c:2641:13 [opt]
frame #6: 0x0000000100437eac php`php_execute_script(primary_file=<unavailable>) at main.c:2681:9 [opt] [artificial]
frame #7: 0x00000001005c7e0c php`do_cli(argc=<unavailable>, argv=<unavailable>) at php_cli.c:951:5 [opt]
frame #8: 0x00000001005c6af8 php`main(argc=<unavailable>, argv=0x0000000102f9c9b0) at php_cli.c:1362:18 [opt]
frame #9: 0x000000019b551d54 dyld`start + 7184
(lldb)
PHP Version
PHP 8.5.2 (cli) (built: Feb 11 2026 07:55:48) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.5.2, Copyright (c) Zend Technologies
with Zend OPcache v8.5.2, Copyright (c), by Zend Technologies
Operating System
MacOS / ARM64
Reactions are currently unavailable