Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QJSEngine cleanup/destructor
QtWS25 Last Chance

QJSEngine cleanup/destructor

Scheduled Pinned Locked Moved Solved General and Desktop
qjsenginejavascriptqt 5.12destructorcleanup
14 Posts 3 Posters 3.0k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Y Offline
    Y Offline
    yah_nosh
    wrote on 13 Apr 2019, 12:37 last edited by yah_nosh
    #1

    Hi all,

    I'm putting together an application using Qt 5.12, where users will load JS scripts that interact with the app through its API. These scripts are bundled into "projects" (i.e multiple JS modules that depend on each other), and at any time I want only one project to be loaded into the JS engine, so if the user loads a different project, I want the previous context to be cleaned up.

    Based on the documentation, I assumed that if I just delete the QJSEngine object and create a new one, this will allow me to create a fresh JS context.

    QJSEngine* jsEngine = new QJSEngine();
    
    // Load JS modules and run code...
    
    jsEngine->collectGarbage();
    delete jsEngine;
    
    jsEngine = new QJSEngine();
    
    // Load new JS modules...
    

    When I try to run this code, I get an access violation exception at delete jsEngine. This is really strange, because the documentation itself states

    Garbage is not collected from the persistent JS heap during QJSEngine destruction. If you need all memory freed, call collectGarbage manually right before destroying the QJSEngine.
    

    which to me implied that I should be able to do this. I even tried using deleteLater, or making the main window the parent of each QJSEngine I create (and thus have them cleaned up when the app is closed), but the problems persist. For some reason, the moment I have more than one instance of QJSEngine, or if I try to delete an instance at any other time than when the app closes, I get some kind of memory access error.

    Anyone have any ideas? Thanks in advance!

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 13 Apr 2019, 20:28 last edited by
      #2

      Hi and welcome to devnet,

      Do you have a stack trace of the crash ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      Y 1 Reply Last reply 13 Apr 2019, 21:43
      1
      • S SGaist
        13 Apr 2019, 20:28

        Hi and welcome to devnet,

        Do you have a stack trace of the crash ?

        Y Offline
        Y Offline
        yah_nosh
        wrote on 13 Apr 2019, 21:43 last edited by
        #3

        @SGaist Hi, thank you very much.

        Currently, I'm using the below code to try and delete QJSEngine:

        	if (jsEngine)
        	{
        		jsEngine->collectGarbage();
        		jsEngine->deleteLater();
        	}
        

        This crashes the app after it executes. I tried it in a way where I set the parent of the QJSEngine to the main window and do not call deleteLater (i.e I let the window clean it up), but it causes a similar crash. The crash itself is the app triggering a breakpoint is_block_type_valid(header->_block_use)

        This is what I could get out of VS:

        ucrtbased.dll!000007fed011c2f1()    Unknown
        
            ucrtbased.dll!000007fed011f8a5()    Unknown
        
        >    HMARL_Test_Engine.exe!operator delete(void * block) Line 21    C++
        
            HMARL_Test_Engine.exe!operator delete(void * block, unsigned __int64 __formal) Line 16    C++
        
            HMARL_Test_Engine.exe!JSInterface::`scalar deleting destructor'(unsigned int)    C++
        
            Qt5Qmld.dll!QV4::QObjectWrapper::destroyObject(bool lastCall) Line 1107    C++
        
            Qt5Qmld.dll!QV4::MemoryManager::sweep(bool lastSweep, void(*)(const char *) classCountPtr) Line 977    C++
        
            Qt5Qmld.dll!QV4::MemoryManager::~MemoryManager() Line 1225    C++
        
            [External Code]    
        
            Qt5Qmld.dll!QV4::ExecutionEngine::~ExecutionEngine() Line 653    C++
        
            [External Code]    
        
            Qt5Qmld.dll!QJSEngine::~QJSEngine() Line 379    C++
        
            [External Code]    
        
            Qt5Cored.dll!qDeleteInEventHandler(QObject * o) Line 4620    C++
        
            Qt5Cored.dll!QObject::event(QEvent * e) Line 1241    C++
        
            Qt5Widgetsd.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 3752    C++
        
            Qt5Widgetsd.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 3109    C++
        
            Qt5Cored.dll!QCoreApplication::notifyInternal2(QObject * receiver, QEvent * event) Line 1061    C++
        
            Qt5Cored.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 1452    C++
        
            Qt5Cored.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1800    C++
        
            Qt5Cored.dll!QEventDispatcherWin32::sendPostedEvents() Line 1093    C++
        
            qwindowsd.dll!QWindowsGuiEventDispatcher::sendPostedEvents() Line 82    C++
        
            Qt5Cored.dll!qt_internal_proc(HWND__ * hwnd, unsigned int message, unsigned __int64 wp, __int64 lp) Line 247    C++
        
            [External Code]    
        
            Qt5Cored.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 640    C++
        
            qwindowsd.dll!QWindowsGuiEventDispatcher::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 74    C++
        
            Qt5Cored.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 139    C++
        
            Qt5Cored.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 225    C++
        
            Qt5Cored.dll!QCoreApplication::exec() Line 1364    C++
        
            Qt5Guid.dll!QGuiApplication::exec() Line 1780    C++
        
            Qt5Widgetsd.dll!QApplication::exec() Line 2910    C++
        
            HMARL_Test_Engine.exe!main(int argc, char * * argv) Line 10    C++
        
            HMARL_Test_Engine.exe!WinMain(HINSTANCE__ * __formal, HINSTANCE__ * __formal, char * __formal, int __formal) Line 104    C++
        
            [External Code]
        

        Let me know if you need any additional info. Also, apologies if the formatting is suboptimal.

        1 Reply Last reply
        0
        • Y Offline
          Y Offline
          yah_nosh
          wrote on 22 Apr 2019, 23:05 last edited by
          #4

          Anyone have any ideas?

          1 Reply Last reply
          0
          • S Offline
            S Offline
            SGaist
            Lifetime Qt Champion
            wrote on 23 Apr 2019, 20:48 last edited by
            #5

            Did you already check the bug report system for something related ?

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            Y 1 Reply Last reply 23 Apr 2019, 21:26
            0
            • S SGaist
              23 Apr 2019, 20:48

              Did you already check the bug report system for something related ?

              Y Offline
              Y Offline
              yah_nosh
              wrote on 23 Apr 2019, 21:26 last edited by
              #6

              @SGaist Yeah, I looked around, nobody seems to have the same problem. Should I report it there?

              Also, just to clarify: I should be able to create and destroy QJSEngine objects this way? So it's not like I'm trying to make the framework do something it's not supposed to?

              1 Reply Last reply
              0
              • S Offline
                S Offline
                SGaist
                Lifetime Qt Champion
                wrote on 24 Apr 2019, 21:59 last edited by
                #7

                Although I haven't used that class extensively, I am not aware of such a limitation. So go on and create a report. Please provide a minimal compilable example.

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                Y 1 Reply Last reply 25 Apr 2019, 21:59
                2
                • S SGaist
                  24 Apr 2019, 21:59

                  Although I haven't used that class extensively, I am not aware of such a limitation. So go on and create a report. Please provide a minimal compilable example.

                  Y Offline
                  Y Offline
                  yah_nosh
                  wrote on 25 Apr 2019, 21:59 last edited by
                  #8

                  @SGaist While making the minimal compilable example, I managed to find the actual source of the problem. It wasn't the destructor at all, at least not directly, but instead me exposing my "interface" to JavaScript. Below is a small example:

                  QJSEngine* jsEngine = new QJSEngine();
                  
                  // Add ourselves to the JS engine
                  QJSValue interface = jsEngine->newQObject(interfacePtr);
                  
                  // Expose interface in the global namespace
                  jsEngine->globalObject().setProperty("INTERFACE", interface);
                  
                  // Do stuff...
                  
                  delete jsEngine; // <-- error happens here
                  
                  

                  It seems that using newQObject causes trouble once I try destroying the QJSEngine, and the documentation references this as well:

                  If the given object is deleted outside of the engine's control, any attempt to access the deleted QObject's members through the JavaScript wrapper object (either by script code or C++) will result in a script exception.

                  So I suspect I need to "clean up" this object before deleting the engine, otherwise (presumably) some ownership issues come up when the JS heap is cleaned up. Unfortunately, I have no idea how to fix this. I tried using deleteProperty on the global object, but that did not work.

                  JonBJ 1 Reply Last reply 25 Apr 2019, 22:10
                  1
                  • Y yah_nosh
                    25 Apr 2019, 21:59

                    @SGaist While making the minimal compilable example, I managed to find the actual source of the problem. It wasn't the destructor at all, at least not directly, but instead me exposing my "interface" to JavaScript. Below is a small example:

                    QJSEngine* jsEngine = new QJSEngine();
                    
                    // Add ourselves to the JS engine
                    QJSValue interface = jsEngine->newQObject(interfacePtr);
                    
                    // Expose interface in the global namespace
                    jsEngine->globalObject().setProperty("INTERFACE", interface);
                    
                    // Do stuff...
                    
                    delete jsEngine; // <-- error happens here
                    
                    

                    It seems that using newQObject causes trouble once I try destroying the QJSEngine, and the documentation references this as well:

                    If the given object is deleted outside of the engine's control, any attempt to access the deleted QObject's members through the JavaScript wrapper object (either by script code or C++) will result in a script exception.

                    So I suspect I need to "clean up" this object before deleting the engine, otherwise (presumably) some ownership issues come up when the JS heap is cleaned up. Unfortunately, I have no idea how to fix this. I tried using deleteProperty on the global object, but that did not work.

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on 25 Apr 2019, 22:10 last edited by
                    #9

                    @yah_nosh
                    Does https://stackoverflow.com/questions/26177693/qjsengine-deletes-my-qobject-how-to-change-ownership-after-qjsenginenewqobjec (QQmlEngine::setObjectOwnership()) help your situation at all?

                    Y 1 Reply Last reply 25 Apr 2019, 22:19
                    3
                    • Y Offline
                      Y Offline
                      yah_nosh
                      wrote on 25 Apr 2019, 22:12 last edited by
                      #10

                      Okay, found the solution. I needed to change the ownership using QQmlEngine::setObjectOwnership, and the JS engine stops trying to delete my objects. So technically there was no bug at all, but the source code and documentation sorely needs an update.

                      1 Reply Last reply
                      3
                      • JonBJ JonB
                        25 Apr 2019, 22:10

                        @yah_nosh
                        Does https://stackoverflow.com/questions/26177693/qjsengine-deletes-my-qobject-how-to-change-ownership-after-qjsenginenewqobjec (QQmlEngine::setObjectOwnership()) help your situation at all?

                        Y Offline
                        Y Offline
                        yah_nosh
                        wrote on 25 Apr 2019, 22:19 last edited by
                        #11

                        @JonB Yeah, sorry, posted my comment right before I noticed yours. It's really unintuitive that the solution is buried in a derived class static function... which apparently uses the base class code anyway.

                        1 Reply Last reply
                        0
                        • S Offline
                          S Offline
                          SGaist
                          Lifetime Qt Champion
                          wrote on 26 Apr 2019, 21:29 last edited by
                          #12

                          @yah_nosh said in QJSEngine cleanup/destructor:

                          Okay, found the solution. I needed to change the ownership using QQmlEngine::setObjectOwnership, and the JS engine stops trying to delete my objects. So technically there was no bug at all, but the source code and documentation sorely needs an update.

                          You should consider improving the documentation and submit a patch for that so everybody can benefit from the outcome of your findings.

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          Y 1 Reply Last reply 3 May 2019, 12:26
                          2
                          • S SGaist
                            26 Apr 2019, 21:29

                            @yah_nosh said in QJSEngine cleanup/destructor:

                            Okay, found the solution. I needed to change the ownership using QQmlEngine::setObjectOwnership, and the JS engine stops trying to delete my objects. So technically there was no bug at all, but the source code and documentation sorely needs an update.

                            You should consider improving the documentation and submit a patch for that so everybody can benefit from the outcome of your findings.

                            Y Offline
                            Y Offline
                            yah_nosh
                            wrote on 3 May 2019, 12:26 last edited by
                            #13

                            @SGaist Yeah, I think as soon as this project is done, I'll append the relevant parts in the QJSEngine docs so others can avoid this headache. Can anyone contribute to the documentation?

                            1 Reply Last reply
                            1
                            • S Offline
                              S Offline
                              SGaist
                              Lifetime Qt Champion
                              wrote on 3 May 2019, 12:55 last edited by
                              #14

                              Anyone can contribute to the documentation, the code, etc. You have to follow the procedures and rules but it's not some walled garden.

                              Interested in AI ? www.idiap.ch
                              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                              1 Reply Last reply
                              2

                              • Login

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • Users
                              • Groups
                              • Search
                              • Get Qt Extensions
                              • Unsolved