diff --git a/NEWS b/NEWS index 511a899e527a..6741674e1eff 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,10 @@ PHP NEWS . Fixed bug GH-23106 (mb_strpos() reads past the end of a haystack ending in a truncated UTF-8 sequence). (Lazizbek Ergashev) +- Opcache: + . Fixed GH-23679 (tracing JIT writes a parent private property into a + child's shadowing public property). (Ilia Alshanetsky) + - PGSQL: . Fixed pg_lo_write() rejecting data containing null bytes. (Ilia Alshanetsky) diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 76510743d333..1e95d80456be 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -650,6 +650,11 @@ static zend_property_info* zend_get_known_property_info(const zend_op_array *op_ } if (info->flags & ZEND_ACC_PUBLIC) { + if ((info->flags & ZEND_ACC_CHANGED) + && op_array->scope + && op_array->scope != ce) { + return NULL; + } return info; } else if (on_this) { if (ce == info->ce) { diff --git a/ext/opcache/tests/jit/gh23679.phpt b/ext/opcache/tests/jit/gh23679.phpt new file mode 100644 index 000000000000..8b3c65c6567f --- /dev/null +++ b/ext/opcache/tests/jit/gh23679.phpt @@ -0,0 +1,116 @@ +--TEST-- +GH-23679: tracing JIT must not write a parent private property into a child's shadowing public property +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.protect_memory=1 +opcache.jit=tracing +opcache.jit_hot_loop=1 +opcache.jit_hot_func=1 +opcache.jit_hot_return=1 +opcache.jit_hot_side_exit=1 +--EXTENSIONS-- +opcache +--FILE-- +arr[$k] = $v; + return $x; + } + + public function setAll($v) + { + $x = clone $this; + $x->arr = $v; + return $x; + } + + public function inc() + { + $x = clone $this; + $x->n++; + return $x; + } + + public function addN($k) + { + $x = clone $this; + $x->n += $k; + return $x; + } + + public function getDim($k) + { + return $this->arr[$k] ?? 'MISSING'; + } + + public function getN() + { + return $this->n; + } +} + +class B extends A +{ + public $arr = []; + public $n = 100; +} + +for ($i = 0; $i < 50; $i++) { + (new A)->setDim('x', 1)->getDim('x'); + (new A)->setAll(['x' => 1])->getDim('x'); + (new A)->inc()->getN(); + (new A)->addN(5)->getN(); + + $b = new B; + $b->arr = ['keep' => 1]; + $b->n = 100; + + $r = $b->setDim('x', 2); + if ($r->getDim('x') !== 2 || $r->arr !== ['keep' => 1]) { + echo "dim-assign i=$i private="; + var_dump($r->getDim('x')); + echo "dim-assign i=$i public="; + var_dump($r->arr); + exit(1); + } + + $r = $b->setAll(['y' => 4]); + if ($r->getDim('y') !== 4 || $r->arr !== ['keep' => 1]) { + echo "assign i=$i private="; + var_dump($r->getDim('y')); + echo "assign i=$i public="; + var_dump($r->arr); + exit(1); + } + + $r = $b->inc(); + if ($r->getN() !== 1 || $r->n !== 100) { + echo "inc i=$i private="; + var_dump($r->getN()); + echo "inc i=$i public="; + var_dump($r->n); + exit(1); + } + + $r = $b->addN(5); + if ($r->getN() !== 5 || $r->n !== 100) { + echo "assign-op i=$i private="; + var_dump($r->getN()); + echo "assign-op i=$i public="; + var_dump($r->n); + exit(1); + } +} +echo "ok\n"; +?> +--EXPECT-- +ok