Uploaded image for project: 'Qt for Python'
  1. Qt for Python
  2. PYSIDE-2482

QWidget deleteLater in QLayout causes memory corruption/hard crash in notify_helper

    XMLWordPrintable

Details

    • Bug
    • Resolution: Invalid
    • Not Evaluated
    • None
    • 5.15.2
    • PySide
    • None
    • Ubuntu 22.04.3
      Python 3.10.8
      PySide 5.15.2
      Qt 5.15.2
    • Linux/X11

    Description

      When calling widget.deleteLater() on a QWidget that lives inside a QLayout, the main UI event processing loop gets corrupted leading to QEvent pointers being passed around that are pointing to QWidgetItem objects and not QEvent objects (thus violating the core event API). This leads to exceptions & hard crashes when those objects are getting treated as QEvents (both in Python & C++).

      This means deleteLater cannot safely be called from PySide at all on a QWidget (as almost all QWidgets tend to live inside some form of QLayout).

      If you run the following attached reproducible test case deleteLater1.py you can clearly see the corruption (note the QWidgetItem object being passed as a QEvent object). You might have to move the mouse across the widget/resize/move the widget to trigger this bug:

      Traceback (most recent call last):
        File "./deleteLater1.py", line 17, in eventFilter
          return QObject.eventFilter(self, obj, event) 
      TypeError: 'PySide2.QtCore.QObject.eventFilter' called with wrong argument types:
        PySide2.QtCore.QObject.eventFilter(QWidget, QWidgetItem)
      Supported signatures:
        PySide2.QtCore.QObject.eventFilter(PySide2.QtCore.QObject, PySide2.QtCore.QEvent)
      

      The hard crash happens inside qtbase/src/widgets/kernel/qapplication.cpp:

      bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
      ...
          // send to all receiver event filters
          if (sendThroughObjectEventFilters(receiver, e)) {
              filtered = true;
              return filtered;
          }
      
          // deliver the event 
          consumed = receiver->event(e);  <--- CRASH
      ...
      

      It looks like the issue is located inside the 100s of lines of code in the QWidget/QObject destructors, where the layout & parent unhooking are taking place. This could be compounded by the Xcb event loop running in a secondary thread on Linux/X11.

      Calling setParent(None) (instead of deleteLater()) produces similar problematic results.

      See also QTBUG-55961

      Attachments

        1. deleteLater.cc
          2 kB
        2. deleteLater1.py
          0.7 kB
        3. deleteLaterMaya.py
          0.6 kB
        4. deleteLaterPyQt.py
          0.7 kB
        5. pyside2482_log.txt
          17 kB
        6. pyside2482_nonlayout.py
          3 kB
        7. pyside2482.py
          3 kB

        Issue Links

          For Gerrit Dashboard: PYSIDE-2482
          # Subject Branch Project Status CR V

          Activity

            People

              crmaurei Cristian Maureira-Fredes
              teijo Teijo Holzer
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: