Skip to content

Commit 36037a1

Browse files
committed
Fix phpGH-20890: Segfault in zval_undefined_cv with non-simple property hook with minimal tracing JIT
This is similar to f6c2e40 but for minimal JIT + tracing JIT. Most of the times the tracing JIT shouldn't rely on going to the VM, but in some cases, like in minimal JIT, it can and then it hits the same bug. Closes phpGH-20897.
1 parent 3f3499f commit 36037a1

3 files changed

Lines changed: 48 additions & 0 deletions

File tree

‎NEWS‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.4.28
44

5+
- Opcache:
6+
. Fixed bug GH-20890 (Segfault in zval_undefined_cv with non-simple property
7+
hook with minimal tracing JIT). (ndossche)
58

69
22 Oct 2026, PHP 8.4.27
710

‎ext/opcache/jit/zend_jit_trace.c‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,14 @@ static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op
333333
// TODO: recompilation may change target ???
334334
return 0;
335335
#endif
336+
case ZEND_FETCH_OBJ_R:
337+
if (opline->op2_type == IS_CONST) {
338+
const zend_class_entry *ce = opline->op1_type == IS_UNUSED ? op_array->scope : NULL;
339+
if (!ce || !(ce->ce_flags & ZEND_ACC_FINAL) || ce->num_hooked_props > 0) {
340+
return 1;
341+
}
342+
}
343+
break;
336344
case ZEND_RETURN_BY_REF:
337345
case ZEND_RETURN:
338346
/* return */

‎ext/opcache/tests/jit/gh20890.phpt‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
GH-20890 (Segfault in zval_undefined_cv with non-simple property hook with minimal tracing JIT)
3+
--CREDITS--
4+
Moonster8282
5+
--EXTENSIONS--
6+
opcache
7+
--INI--
8+
opcache.jit=1251
9+
--FILE--
10+
<?php
11+
class HookJIT {
12+
private int $readCount = 0;
13+
14+
public int $computed {
15+
get {
16+
$this->readCount++;
17+
return $this->readCount * 2;
18+
}
19+
}
20+
}
21+
22+
function hook_hot_path($obj, $iterations) {
23+
$sum = 0;
24+
for ($i = 0; $i < $iterations; $i++) {
25+
$sum += $obj->computed;
26+
}
27+
return $sum;
28+
}
29+
30+
echo "Testing property hook in hot path...\n";
31+
$obj = new HookJIT();
32+
$result = hook_hot_path($obj, 100);
33+
echo "Result: $result\n";
34+
?>
35+
--EXPECT--
36+
Testing property hook in hot path...
37+
Result: 10100

0 commit comments

Comments
 (0)