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

QQuickWidget crash on app quit if it is inside a QWidget and contains a QWebView that had loaded content

    XMLWordPrintable

Details

    • Windows
    • 56fadb571f32b721d8b99554e6e38692009ec37f

    Description

      I have a qml file with a QWebView (the one from qml). It is loaded with a QQuickWidget that itself is contained inside a subclassed QWidget. 

      Quitting the application fails with an error.

      This can be reproduced with the attached example.

      Update 24.02.: I figured out a workaround. It ensures that all QWidgets which contain a QQuickWidget (with a QWebView) are destroyed before quitting the application. Somehow I cannot upload another file so I added the code at the end of this post.

      In the example I tested different combinations:

      The error occurs, if:

      • The qml is created inside the constructor of the widget, or later passed as a pointer AND
      • The QWebView must have loaded content (either via "url"-parameter or via "loadHTML"), before quitting the app

      The error does not occur, if I create the QQuickWidget in main() and pass it by reference to the QWidget. But that is probably some side effect, The main issue seems to be with deletion of the context, I guess.

      Debug output is

      {{}}

      [11328:19036:0223/150952.613:FATAL:render_process_host_impl.cc(887)] Check failed: map_.empty()

      {{}}

      I found a post with the same error message, see answer from "yan12125"

      https://github.com/nextcloud/desktop/issues/941

      which was solved by a patch that corrects the deallocation order:

      https://github.com/electron/electron/pull/15028

       

      The complete stacktrace is 

      {{}}

      [11328:19036:0223/150952.613:FATAL:render_process_host_impl.cc(887)] Check failed: map_.empty(). Backtrace: QWebEngineUrlSchemeHandler::_q_destroyedUrlSchemeHandler [0x11B4E857+810583] QWebEngineUrlSchemeHandler::_q_destroyedUrlSchemeHandler [0x11B5BD11+865041] QWebEngineUrlSchemeHandler::_q_destroyedUrlSchemeHandler [0x11A93A9E+45214] QtWebEngineCore::JavaScriptDialogController::qt_static_metacall [0x1166ED0A+32480538] QtWebEngineCore::JavaScriptDialogController::qt_static_metacall [0x1167185F+32491631] GetHandleVerifier [0x12ED8CE9+20263193] IsSandboxedProcess [0x1403328B+16485723] IsSandboxedProcess [0x13A93802+10588882] IsSandboxedProcess [0x1406445F+16686895] IsSandboxedProcess [0x14063EDD+16685485] QtWebEngineCore::JavaScriptDialogController::qt_static_metacall [0x10406C6D+13180029] QtWebEngineCore::JavaScriptDialogController::qt_static_metacall [0x10406C41+13179985] IsSandboxedProcess [0x13D95555+13742117] QWebEngineUrlSchemeHandler::_q_destroyedUrlSchemeHandler [0x11AC020E+227342] QWebEngineUrlSchemeHandler::_q_destroyedUrlSchemeHandler [0x11AC0148+227144] QWebEngineUrlSchemeHandler::_q_destroyedUrlSchemeHandler [0x11ABF94F+225103] QWebEngineUrlSchemeHandler::_q_destroyedUrlSchemeHandler [0x11ABF96F+225135] QWebEngineUrlSchemeHandler::_q_destroyedUrlSchemeHandler [0x11ABFA2C+225324] QtWebEngineCore::JavaScriptDialogController::qt_static_metacall [0x1115CC69+27163769] QtWebEngineCore::ProfileAdapterClient::downloadInterruptReasonToString [0x0F70855F+2623] QtWebEngineCore::ProfileAdapterClient::downloadInterruptReasonToString [0x0F7086A6+2950] QtWebEngineCore::ProfileAdapterClient::downloadInterruptReasonToString [0x0F70888F+3439] QtWebEngineCore::ProfileAdapter::checkPermission [0x0F705B56+230] QtWebEngineCore::FilePickerController::mode [0x0F71EDBA+33066] QtWebEngineCore::ProfileAdapter::~ProfileAdapter [0x0F7054E6+246] QtWebEngineCore::ProfileAdapter::~ProfileAdapter [0x0F7055DD+493] QtWebEngineCore::WebEngineSettings::setWebContentsAdapter [0x0F69BCEA+3418] QtWebEngineCore::WebContentsAdapter::requestedUrl [0x0F741E5A+746] QWebEngineUrlScheme::operator!= [0x0F74BB8B+3707] QWebEngineUrlScheme::operator!= [0x0F74BCB7+4007] QTextCodec::codecForHtml [0x5F98A3C2+3390559] QTreeViewPrivate::layout [0x609525D6+456449] main [0x001F6D24+628] (d:\anonymous\qml-user-js-crash\userjs\main.cpp:67) WinMain [0x001F664D+173] (c:\users\qt\work\qt\qtbase\src\winmain\qtmain_win.cpp:104) invoke_main [0x001F50AE+30] (d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:107) __scrt_common_main_seh [0x001F4F47+343] (d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288) __scrt_common_main [0x001F4DDD+13] (d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:331) WinMainCRTStartup [0x001F5128+8] (d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_winmain.cpp:17) BaseThreadInitThunk [0x7694343D+18] RtlInitializeExceptionChain [0x776A9802+99] RtlInitializeExceptionChain [0x776A97D5+54]

      {{}}

       Workaround code:

      workaround.h

      #ifndef WORKAROUND_H
      #define WORKAROUND_H
      
      #include <QPointer>
      
      // QT-BUG https://bugreports.qt.io/browse/QTBUG-74021
      class Viewer;
      class ViewerCleanupRegistry{
          ViewerCleanupRegistry(){}
          QList<QPointer<Viewer> > viewers_;
      public:
          ViewerCleanupRegistry(const ViewerCleanupRegistry &other) = delete;
          void operator=(const ViewerCleanupRegistry &other) = delete;
          void registerViewer(Viewer *v);
          static ViewerCleanupRegistry& instance();
          void cleanup();
      };
      
      #endif // WORKAROUND_H
      

      workaround.cpp

      #include "workaround.h"
      #include "viewer.h"
      
      ViewerCleanupRegistry &ViewerCleanupRegistry::instance(){
          static ViewerCleanupRegistry v;
          return v;
      }
      
      void ViewerCleanupRegistry::cleanup(){
          for ( auto &v : viewers_ ){
              if (v.isNull()){
                  viewers_.removeOne(v);
              }else{
                  const_cast<Viewer *>(v.data())->deleteLater();
                  viewers_.removeOne(v);
              }
          }
      }
      
      void ViewerCleanupRegistry::registerViewer(Viewer *v){
          viewers_.append(QPointer<Viewer>(v));
      }
      
      

      In the Constructor of Viewer, call

      ViewerCleanupRegistry::instance().registerViewer(this);
      

      Then quit the app like this and no crash occurs:

      trayMenu.addAction("Exit",[&](){
              ViewerCleanupRegistry::instance().cleanup();
              qApp->quit();
      });
      

      Attachments

        For Gerrit Dashboard: QTBUG-74021
        # Subject Branch Project Status CR V

        Activity

          People

            michal Michal Klocek
            thomas.rusche Thomas Rusche
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes