How to debug PySide2 silent crashes?
-
Hello,
My specifications are:
Windows 10
Python==3.6.8
PySide2==5.15.2I have a pretty big closed source application, so it's really hard to create a minimal example. But the general concept is a nodeeditor. I'm trying at the moment to pinpoint the real issue. My application uses QGraphicsView, QGraphicsScene, QGraphicsItem, QGraphicsProxyWidget etc. Crash occasionally happens when i move the mouse around.
To pinpoint the issue, I have wrapped every function in my application for tracing, used "faultHandler", used sys.settrace and crash seems to happens inside event loop. Only error i get is:
Windows fatal exception: access violation
The error above is thrown on the line below:
sys.exit(app.exec_())
I've been reading through the internet for two weeks, tried many things, could not find a solution/practice. I know what i provide is near to nothing but Is there a better way to debug my application?
-
@JonB , thank you for responding. I'm using Windows Command Prompt with the command below, since most IDE's monkey patch sys.traceback:
python -m -q -X faulthandler main.py
Sometimes application crashes with a traceback with same Windows Fatal Exception, but these are pretty random and inconsistent, sometimes happens inside native Python modules, sometimes in requests.send etc. I believe they are caused by interruption when main thread dies.
-
@deahran It's kind of tricky to track errors when the program is called main.py.
Do you have something like this to start your code?:
class MainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) . . . if __name__ == '__main__': app = QApplication(sys.argv) mainApp = MainWindow() mainApp.show() sys.exit(app.exec_())
-
Sadly, if i run the application in PyCharm debug mode and the application freezes/crashes, somehow PyCharm can't reach any frame due to internal C errors, which is only shown by faulthandler module, The traceback from faulthandler always and only pinpoints to sys.exit(app.exec_()), where the event loop starts.
I have been expecting a memory leak, invalid shiboken2 wrappers inside events, infinite looping and could not find any.
The one issue i was able to pinpoint was if i were to use QWidget.setStyleSheet("...") frequently in a mouseMoveEvent for a QWidget inside QGraphicsScene, it also causes a a lot of silent crashes. Removing that line improved the issue a lot.
Thank you for responding. I would love to provide a minimal example. But i can not since the application is closed source and pretty big. I'm preparing a one right now but will take quite some time.
-
@deahran I usually add temporary print functions to my code so that I can see in a terminal console where my program is going and how often. Something like:
def calc_bitcoin(amount_sold): print('Before.....') value = amount_sold / 0.0 print('After!!! Did I make it to this point or not??????')
-
@Shawn-Driscoll i like to hodl :). Jokes aside, i've tried that approach too. Crash seems to happen right after
QGraphicsScene.drawBackGround()
,QGraphicsView.mouseMoveEvent()
or other keyboard-mouse events finish returning. I also examined the outer frame with the function below. When these paint or event methods are called, the outer frame points to my main.py.import sys from itertools import count def stack_size2a(size=2): """Get stack size for caller's frame. """ frame = sys._getframe(size) for size in count(size): frame = frame.f_back if not frame: return size
Also my drawBackGround function , i always see the function return part before crash:
class MyScene(QGraphicsScene): . . . def drawBackground(self, painter, rect): if DEBUG: print("graphics_scene.paint -> entering") super().drawBackground(painter, rect) if DEBUG: print("graphics_scene.paint -> called super") # here we create our grid left = int(math.floor(rect.left())) right = int(math.ceil(rect.right())) top = int(math.floor(rect.top())) bottom = int(math.ceil(rect.bottom())) first_left = left - (left % self.grid_size) first_top = top - (top % self.grid_size) # all lines to be drawn lines_light, lines_dark = [], [] for x in range(first_left, right, self.grid_size): if (x % (self.grid_size*self.gridSquares) != 0): lines_light.append(QLine(x, top, x, bottom)) else: lines_dark.append(QLine(x, top, x, bottom)) for y in range(first_top, bottom, self.grid_size): if (y % (self.grid_size*self.gridSquares) != 0): lines_light.append(QLine(left, y, right, y)) else: lines_dark.append(QLine(left, y, right, y)) if DEBUG: print("graphics_scene.paint -> lines light:", lines_light) if DEBUG: print("graphics_scene.paint -> lines dark:", lines_dark) # draw the lines painter.setPen(self._pen_yellow) # self._pen_yellow = QPen("yellow") painter.drawLines(lines_light) painter.setPen(self._pen_black) # self._pen_black = QPen("black") painter.drawLines(lines_dark) if DEBUG: print("graphics_scene.paint -> lines drawn, function return.")
-
@deahran
If you think something in yourdrawBackground()
code is causing the crash, keep commenting out lines till it goes away! Or not, if you get down to nothing but calling the base implementation. In which case it's something else!I know it's laborious/not easy, but really if you are getting a crash and debugger/print statements aren't helping that's what to do....
How does:
def drawBackground(self, painter, rect): pass
behave?!
What about with only
super().drawBackground(painter, rect)
in it? What about if you comment out the# draw the lines
section at the bottom? What about if you remove your wholedef drawBackground()
override? -
I would like to provide update on my situation. Problem seems to be resolved. I'm not %100 percent sure since it's hard to reproduce the crash.
I used a JIT debugger (IDA) to see what happens during crash, which showed me errors were happening because of a segmentation error (SIGSEGV) inside
Qt5Widgets.dll->...->QGraphicsItem::topLevelItem->...
. Which implies Qt is trying to read some value by pointer from memory, but can not. The changes i made:- There were some QGrahpicsItems with
paint()
method drawing outside ofboundingRect()
. Made sure all painting events stays insideboundingRect()
. - Made sure before changes to
boundingRect()
,prepareGeometryChange()
was called (QGraphicsItem, QGraphicsPathItem)
Special thanks to all who replied.
- There were some QGrahpicsItems with