-
Notifications
You must be signed in to change notification settings - Fork 345
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): Natron crashes after repeatedly opening and closing a custom pypanel with a simple QPushButton #1029
Comments
Hi @acolwell ! here i provide an initGui.py script. Just pop it off somewhere and set the NATRON_PLUGIN_PATH to the containing folder of the script. Find here attached an example of a the crash. natron_test.mp4
Thanks. |
@Emmett-Brown82 thanks for the plugin and repro video. I am able to reproduce this crash locally on Windows. I'm a little busy today and tomorrow, but I'll try to figure out what is causing this crash sometime this week. |
@acolwell you are welcome! If it helps, i think the problem could be related maybe to the way we retrieve the panel. In PySide1/2 it is well known that you need to retrieve the widget, not by a python variable, but doing the: self.findChild(QtWidgets.QWidget, "[widgetObjectName]") because retrieving the widgets this way makes sure the reference counter doesnt go to 0 and hence the C++ widget pointer is not accidentally deleted. My bet, the problem is related to something like that. Plus, if you have a look at the backtrace: it is the QApplication.instance().focusChanged signal emitted what is causing the memory access violation. Probably because the newly created widget doesnt exist anymore and the python variable exists, but the C++ object it is referencing, doesnt anymore. Hope it helps. By the way, it has the same behaviour with Natron 2.5.0 Official Release (PySide/Qt4). Side note: i have experience integrating different plugins in different DCCs and one thing i dont understand is that, the UI is based on Qt right? then how come i am able to create a QApplication([]) inside Natron?? Shouldnt that be created by default? Thanks for the effort @acolwell . Let me know if i can be of any help in the meantime. Best, |
So I'm going to preface this with a few things. I am a relatively new developer working on Natron. I've only been working on the project for 2 years and I have not done much with python plugins or the python bindings. The vast majority of the code was written before I got involved so I don't have any historical context as to why things are the way they are. I can only tell you what I observe the code doing and what the documentation states. Here is what I've found so far:
In general, I agree that Natron should not crash even if the python code is not quite right. I'm still trying to figure out what exactly the intended behavior/control flow/lifetimes are supposed to be so please bear with me. In the meantime, I hope these few findings might help you modify your code so you an avoid the crashing behavior for now. I'll keep digging to see if I can make Natron more robust in this area. |
Hi @acolwell thanks for the effort and your quick reply.
You will notice the exact same code as u suggested but with three "JC Tweak Test 1, 2,3" in lines ranging from 177-190. Those three tests are independent to one another. I made this to prove my point:
Test 1: No QWidget / Panel destroyed! ==> when closing the tabWidget apparently the Qt object is still alive, so appending it again and removing, appending without destroying it, works Ok. Unfortunately, for the purposes of integrating Natron into a set of tools, we should be able to recreate the widget: destroying it and then creating it again by allocating a new pointer. Test 2: Do destroy the widget "ala" Qt mode: call from which doesnt destroy the widget in Natron, and the set the parent's widget to None and call deleteLater() Qt destructor in the next Qt event loop. Result: this causes a crash after repeatedly reopening the panel. (see attached .mp4) natron-test-2.mp4Test 3: Do destroy the panel but this time by calling which does destroy the widget. Result: still same crash.
I will try to download the source code and have a look as well, although it is been ages since i havent coded in C++, so, in that sense, bear with me as well a little bit ;). As soon as i have any piece of news i ll let u know. UPDATE: if you test exclusively the code provided by the official docs you got after several clicks when opening the IconViewer a crash. Try it not editing the code with the <JC Tweak Test 1,2,3>, you will notice it crashes. (just leave the print inside the <if hasattr(...)> UPDATE 2: the Qt event loop is working fine. The widgets are capturing the events correctly, so basically, the QApplication class instance and the lack of it in Natron, may not be exactly the problem. The focus IMHO should be put in the lifetime cycle of QWidgets. The problem is not how PySide1/2 manages QWidgets' lifetime, but rather, how Natron handles Qt objects when destroying them, as you stated in your last post. I totally agree with that. Following this, i will try to provide documentation, but QWidgets pointers are "reference-counted" in Qt. My hint would be to try to track down when this count is zero and see if it makes sense that the object being destroyed. I wouldnt mind to help by videoconferencing at some point if needed. Best, |
@Emmett-Brown82 thanks for your responses and patience. I believe I found the source of the crashes and I created pull request #1030 that I believe should fix them. Basically pointers to deleted widgets were getting used and triggering crashes. You should be able to try out your code in this Windows installer build that I did before creating the pull request. This is not an official build obviously, but it does contain the fix in the pull request and it would give you an opportunity to test the fix ASAP. |
Hi @acolwell ! Thanks for the effort. Everything is working fine now. I am able to close (destroy the widget) and create it again. I also noticed you already modified the docs as claimed in your #1030 . I believe the two existing methods: removeTab() and closeTab() are now merged into only removeTab() which takes the role of the latter in not only removing the widget but also destroying it. Can i ask when are we expecting the 2.6.0 release? or, if it is really taking more time, is there a 2.5.1 Official release planned for the next days? it would be awesome to have this fix delivered as soon as possible, as i believe it is affecting Natron since 2.5.0 Official (Windows and Linux, and PySide1/PySide2), and probably way before this release. Furthermore, i am working in Linux, so i would have to get the Linux Release of Natron 2.X.Y (whichever version should be). Thanks for your work and the quick reply. This was a major fix that affects independent platform releases. If i can do anything else to help, just name it. Best, |
Make sure to follow our issue report guidelines
Natron version
Natron 2.5.0
Operating system
Rocky Linux 8 (as a virtual machine with VMWare Workstation 17.5.2)
System specs
RAM: 32GB
Processor: AMD Ryzen
Graphics Card: Nvidia RTX 2050
Did you install Natron using the official installer?
Custom installation path
/opt/Natron-2.5.0
What were you trying to do?
Hi, i am trying to use the init.py and initGui.py scripts to register a custom pypanel. This custom pypanel only has a QPushButton and i add it through the self.addWidget(self.pushButton) method.
I do a stress test: opening and closing repeatedly the same tab with the button makes Natron crash at the 4th time. This is reproducible in windows and in Rocky linux 8 as well.
There seems to be a problem with the memory management between PySide 1.2.4 (Qt 4.8.7) and Python 3.10.5 (the one that ships with Natron 2.5.0)
The backtrace calls at some point the focusChanged signal of the QApplication. Seems the problem is there.
What did you expect to happen? What happened instead?
(C) 2018-2022 The Natron developers
(C) 2013-2018 INRIA and Alexandre Gauthier-Foichat
Step-by-step reproduction instructions
Additional details
No response
The text was updated successfully, but these errors were encountered: