-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] Property hooks + enabled JIT causes unexpected results (segfault for JIT function) #17376
Comments
Simplified: <?php
abstract class AbstractDecorator {
protected $wrapped;
public function persist()
{
var_dump($this->wrapped);
}
}
class EntityManagerDecorator extends AbstractDecorator {
protected $wrapped {
get {
return $this->proxy;
}
}
public function __construct(private int $proxy)
{
}
}
$em = new EntityManagerDecorator(1234);
$em->persist(); |
Probably, |
We're returning property info for the property but not taking into account that the subclasses may make the property a hook. This causes the property to be read from the property table instead of executing the hook, giving the wrong result. |
It seems with tracing JIT foreach (range(1, 100) as $i) {
call_user_func($fn);
} I think after some iterations will trigger JIT tracing and hook for $wrapped will be return null |
That makes sense, conceptually it's still the same issue I described earlier: there is no real hook codegen support for the JIT. We detect hooks, but only on the parent classes, not the child classes, and then take the slow path. So when a child class uses a hook and the parent class doesn't, the code generated for the parent class mistakingly assumes there is no hook and that breaks things. |
This is indeed unfortunate. I don't see a way to fix this without introducing hook support, but hook support in the JIT is also questionable if hooks are rare, and we generate lots of code that will never run... Optimally, PHP would switch to opt-in inheritance, i.e. class A {
public $prop = 1;
}
class B extends A {
public $prop {
get => 2;
}
}
function test(A $a) {
var_dump($a->prop);
}
test(new A);
test(new B); Slightly simpler example. |
It's only now, but what will be after some years?) Even if disallow extending property with hooks then more people will be use hooks directly in code and someday without JIT it will bottleneck in performance... Should put some warning to documentation about do not use CPU bound calculation in property hooks) In my case I just decide try hooks for abstract ready decorator in Doctrine https://github.com/doctrine/orm/blob/3.3.x/src/Decorator/EntityManagerDecorator.php (instead of full implement from scratch) In big projects using EM - common case and JIT give boost here...) |
I added the "obvious" fix here, I'm not sure if there are other places where similar assumptions are made. Let's wait until Dmitry is back from vacation next week. |
That's very conservative right, even if you don't have a hook the check can trigger on overridden properties and take the slow path? |
@nielsdos It's conservative, but not very (imo). Overriding properties is something that rarely has uses. Excluding hooks, they are:
I'm not sure if the additional load would be offset by the additional properties dodging the slow path. |
Okay right. I was asking because this crossed my mind at one point too but thought it was perhaps too much. |
Yeah, tbf this is all based on assumptions, I did not do any measurements yet. |
Description
Hello, I think I found some bugs here.
The following code:
Case 1: SEGMENTATION FAULT
If run this code, then it will be crash on
$em->persist($a1);
Case 2: Fatal error (unexpected behaviour)
If remove in this code interface EntityManagerInterface and implements statements then it will be give fatal error:
If disable opcache or use tracing mode it will be work as expected:
P.S. I tried test PHP 8.4.3RC1 - bugs also exists there.
PHP Version
PHP 8.4.2
Operating System
Alpine 3.21
The text was updated successfully, but these errors were encountered: