Skip to content

Commit 2d7df09

Browse files
committed
Crash instead of segfault
1 parent 1d48f1a commit 2d7df09

2 files changed

Lines changed: 57 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
.phpunit.result.cache
33
.php-cs-fixer.cache
44
vendor/
5+
tests/jit_crash_code.php

tests/jit_type_error.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
/**
4+
* Minimal self-contained reproduction for PHP JIT tracing CV corruption bug.
5+
* https://github.com/php/php-src/issues/21746
6+
*
7+
* Run: php -d opcache.enable_cli=1 -d opcache.jit=tracing tests/jit_type_error.php
8+
*/
9+
10+
final class LR {
11+
public static function p(mixed $cx, string $name, mixed $context, array $hash, string $indent): string {
12+
try { $result = ''; } finally {}
13+
$lines = explode("\n", $result);
14+
foreach ($lines as $i => $_) { if ($i === 0) break; }
15+
return $result;
16+
}
17+
public static function hbbch(array $positional, ?\Closure $cb): string {
18+
if ($cb && is_array($positional[0] ?? null)) foreach ($positional[0] as $v) $cb($v);
19+
return '';
20+
}
21+
}
22+
23+
$renderCode = <<<'PHP'
24+
<?php
25+
return function (mixed $in = null, array $options = []) {
26+
$a = null;
27+
$b = '';
28+
$c = '';
29+
$d = fn() => '';
30+
$e = fn() => '';
31+
$f = fn() => '';
32+
$g = fn() => '';
33+
return ''
34+
.LR::p(null, '', null, [], '')
35+
.LR::hbbch([null], $d)
36+
.LR::hbbch([null], $e)
37+
.LR::hbbch([null], $f)
38+
.LR::hbbch([null], $g);
39+
};
40+
PHP;
41+
42+
// file_put_contents is required, not just require of an existing file: the fresh mtime
43+
// triggers opcache's file_update_protection, compiling the closure into a transient
44+
// (non-cached) opcode array. The JIT traces this differently, forming the cross-frame
45+
// STOP_LINK path that triggers the CV slot corruption.
46+
$renderFile = __DIR__ . '/jit_crash_code.php';
47+
file_put_contents($renderFile, $renderCode);
48+
$renderer = require $renderFile;
49+
50+
for ($r = 0; $r < 70; $r++) {
51+
echo "Render $r...";
52+
$renderer();
53+
echo "OK\n";
54+
}
55+
56+
echo "--- Completed without crash (JIT may not have been active) ---\n";

0 commit comments

Comments
 (0)