Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-126748

QApplication destructor doesn't release hidden QMenu window resource

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • None
    • 6.5.3
    • None
    • Windows

    Description

      Please use the following code to reproduce. QMenu's native window is leaked after QApplication destruction. It can continue to receive windows messages and cause crashes in Qt window proc.

      In the sample code, I send messages using API for simplicity. There can be other ways to cause the application to process messages. like OleUninitialize in QWindowsContext destructor or AMD audio driver or wacom tablet driver...

      QApplication destructor call destroy(true, true) to release all windows. But hidden QMenu is not handled because it doesn't has WA_NativeWindow flag.

      #include <QtWidgets/QApplication>
      #include <QtWidgets/QMenu>
      #include <QtWidgets/QWidget>
      #include <QtCore/QTimer>
      #include <Windows.h>
      
      HWND leakedWindow = 0;
      
      class WidgetWithMenu : public QWidget
      {
      public:
          WidgetWithMenu(QWidget* parent)
              : QWidget(parent)
          {}
      
          void showEvent(QShowEvent* e) override
          {
              QTimer::singleShot(100, this, [&]() {
                  m_pMenu = new QMenu(this);
                  m_pMenu->popup(QPoint(0, 0));
      
                  QTimer::singleShot(100, this, [&]() {
                      leakedWindow = (HWND)m_pMenu->internalWinId();
                      m_pMenu->hide();
                      window()->close();
      
                      // QMenu's window is a transient child of toplevel window. But QMenu has no
                      // WA_NativeWindow flag. When QApplication destructor call toplevel window
                      // destroy(true, true), QMenu is skipped and leak.
                  });
              });
          }
      
      private:
          QMenu* m_pMenu = nullptr;
      };
      
      int main(int argc, char** argv)
      {
          {
              QApplication app(argc, argv);
      
              QWidget* tlw = new QWidget();
              tlw->resize(640, 480);
              tlw->setStyleSheet("QWidget { background-color: red; }");
      
              QWidget* child = new WidgetWithMenu(tlw);
              child->setGeometry(0, 0, 100, 100);
              child->setStyleSheet("QWidget { background-color: yellow; }");
      
              tlw->show();
              app.exec();
          }
      
          // Qt window proc can still receive messages and crash.
          SendMessage(leakedWindow, WM_SETTINGCHANGE, 0, (LPARAM)TEXT("ThemeChanged"));
          return 0;
      }
      
      

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            qt.team.quick.subscriptions Qt Quick and Widgets Team
            mingxiang Mingxiang Xu
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes