View Issue Details
|0002222: Xdebug holds a reference to objects in the stack trace of a caught exception
I think relating to the 3.3.0 release which fixed some issues with exception.
I am now seeing in a Drupal context that objects are not getting their destructor called sometimes when they should. With Xdebug disabled it calls them normally at the end of the method that created them when their variable goes out of scope.
I think it's related to exceptions being rethrown in some cases perhaps it is "capturing" a reference in a stack and then preventing it from destructing.
|Steps To Reproduce
With Xdebug enabled:
This causes some issues in my case because the object not destructing is a transaction object. And due to destructor order not determined on shutdown most of time the connection is destroyed before the transaction is destroyed and so it causes data loss in my test environment with Xdebug enabled.
|No tags attached.
Sorry the summary needs to be edited - I forgot to update it - it is rather assumptive
If you comment out the
I can also confirm that Xdebug 3.2.2 is working. Downgrading to it and running I get the expected DESTRUCTION before METHOD RETURNED. After upgrading again, back to having destruction last.
So this is definitely caused by 3.3.0
This only occurs when develop is set in xdebug.mode.
Whilst I think it is not great practice for code to rely on the order in which objects are desctructed, I think it is a major bug that changing the xdebug.mode results in such differences.
The script can be even simpler:
Rethrowing is not required.
The problem is as follows:
Xdebug isn't exactly doing anything wrong here.
What happens, is that Xdebug now keeps a reference to the last 8 exceptions, including their stack trace (with local variables).
This script demos that:
Thanks @derick I am getting a better understanding here.
Can you let me know why it is remembering the last 8 exceptions? Is this a feature of some kind in 3.3.0?
Yes, this is indeed a new feature. To be able to do these things:
I don’t quite understand the 8 exceptions though. Shouldn’t it only keep the exception if it is needed? I don’t quite understand why it keeps an exception referenced (along with local variables etc) if it was caught and then went out of scope. In your simpler example I can’t see any debugging path where you would expect or want or need to know about an exception that was handled. And 8 seems arbitrary? I might be really missing something here but I’m struggling to see it
Ok I think I get it now. The 476 bugfix. Capturing extra info when thrown so you can grab the last transaction in the exception handler and also get lots of additional information not normally stored with the trace. Thus it needs to store it separately to the exception in case it is needed in the handler, as there’s not a way to store it in the exception itself.
Question remaining is would that be best under a feature flag and optin due to the extra references and side effects on destruction behaviour or is it aimed to remain as a default enabled. Maybe an opt out option is useful though?
I got bitten by this exact same issue. I rely on some objects that automatically do cleanup in case something throws an exception.
True, strictly speaking xdebug is not really doing anything that is incorrect. It does not change the fact that object cleanup in PHP is deterministic. However, it does change the behavior of applications in subtle ways. I think xdebug should not do that. At least not by default, and not in ways that are not obvious to the user.
For me it was rather frustrating to trace down why my unit tests started failing. Also, I don't think it is wrong for applications to rely on deterministic object cleanup. In fact, it is an incredibly useful feature of the language, as explained by Johannes Schlüter here: https://schlueters.de/blog/archives/184-Destructing-PHP.html
I'm not sure about the solution though. Would it be possible to create copies of local variables in stead? Or maybe xdebug could check if a variable is an object that should be destroyed (''refcount = 1'') due to it going out of scope?
For now I changed my PHP config to use ''xdebug.mode=off'' by default and use ''xdebug.mode=debug'' when debugging. In both cases object cleanup works as expected.
Thanks for looking into this!
I'm still hitting this periodically across environments - upstream on Drupal and across contrib I think it's going to be a good few years before this gets sorted in that ecosystem and I do agree with the above that this is an application behaviour change and breaks expected PHP behaviour.
@dtakken Thanks for the hint on the xdebug.mode - I will try running things without the "develop" flag for now and hopefully that works :)
Would be really great to understand if there is any leeway on a feature flag here - even if it defaults to on like the feature is now - it would mean we could benefit from all the goodness of the "develop" mode without impacting existing applications by setting the flag.
|Note Added: 0006703
|Note Added: 0006704
|Note Added: 0006709
|Note Added: 0006710
|Note Added: 0006711
|Note Added: 0006712
|Note Added: 0006713
|Note Added: 0006714
|Note Added: 0006741
|Note Added: 0006800