Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt WebKit
  4. QWebFrame::evaluateJavaScript crash
QtWS25 Last Chance

QWebFrame::evaluateJavaScript crash

Scheduled Pinned Locked Moved Qt WebKit
11 Posts 2 Posters 5.1k 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.
  • J Offline
    J Offline
    janfaroe
    wrote on last edited by
    #1

    Hi all,

    I'm getting random crashes when I'm trying to run a rather large Javascript script via QWebFrame::evaluateJavaScript(). Is this a bug in webkit, Qt, or could I be doing something wrong?

    Basically, what I'm doing is:

    @QWebPage webPage;
    QWebFrame* webFrame = webPage.mainFrame();
    webFrame->setContent(QString("<script type="text/javascript">" + scriptContent + "</script>").toUtf8());
    // I tried webFrame->evaluateJavaScript(scriptContent) with the same "result"
    QVariant callResult = webFrame->evaluateJavaScript(functionCall);@

    Stack trace:
    @Thread 3 Crashed:: Thread (pooled)
    0 QtWebKit 0x000000010176e8e1 WTFCrash + 113
    1 QtWebKit 0x0000000101795aa3 WTF::StringImpl::~StringImpl() + 339
    2 QtWebKit 0x0000000101795abe WTF::StringImpl::destroy(WTF::StringImpl*) + 14
    3 QtWebKit 0x00000001014ee307 JSC::MarkedBlock::FreeList JSC::MarkedBlock::specializedSweep<(JSC::MarkedBlock::BlockState)3, (JSC::MarkedBlock::SweepMode)1, (JSC::MarkedBlock::DestructorType)1>() + 167
    4 QtWebKit 0x00000001014edd14 JSC::MarkedBlock::FreeList JSC::MarkedBlock::sweepHelper<(JSC::MarkedBlock::DestructorType)1>(JSC::MarkedBlock::SweepMode) + 164
    5 QtWebKit 0x00000001014edb59 JSC::MarkedBlock::sweep(JSC::MarkedBlock::SweepMode) + 73
    6 QtWebKit 0x00000001014ecd1a JSC::MarkedAllocator::allocateSlowCase(unsigned long) + 90
    7 QtWebKit 0x000000010069a003 JSC::JSString::create(JSC::VM&, WTF::PassRefPtrWTF::StringImpl) + 243
    8 QtWebKit 0x0000000100699e7d JSC::jsString(JSC::ExecState*, WTF::String const&) + 157
    9 QtWebKit 0x00000001016e0b98 JSC::JSFunction::finishCreation(JSC::ExecState*, JSC::NativeExecutable*, int, WTF::String const&) + 88
    10 QtWebKit 0x00000001016e0ad5 JSC::JSFunction::create(JSC::ExecState*, JSC::JSGlobalObject*, int, WTF::String const&, long long ()(JSC::ExecState), JSC::Intrinsic, long long ()(JSC::ExecState)) + 229
    11 QtWebKit 0x00000001016cfd03 JSC::FunctionPrototype::addFunctionProperties(JSC::ExecState*, JSC::JSGlobalObject*, JSC::JSFunction**, JSC::JSFunction**) + 467
    12 QtWebKit 0x00000001016e9e76 JSC::JSGlobalObject::reset(JSC::JSValue) + 838
    13 QtWebKit 0x00000001013b17ea WebCore::JSDOMWindowBase::finishCreation(JSC::VM&, WebCore::JSDOMWindowShell*) + 202
    14 QtWebKit 0x00000001013d83e1 WebCore::JSDOMWindow::create(JSC::VM&, JSC::Structure*, WTF::PassRefPtrWebCore::DOMWindow, WebCore::JSDOMWindowShell*) + 161
    15 QtWebKit 0x00000001013b6530 WebCore::JSDOMWindowShell::setWindow(WTF::PassRefPtrWebCore::DOMWindow) + 352
    16 QtWebKit 0x00000001013b639f WebCore::JSDOMWindowShell::finishCreation(JSC::VM&, WTF::PassRefPtrWebCore::DOMWindow) + 31
    17 QtWebKit 0x000000010068e2a8 WebCore::JSDOMWindowShell::create(WTF::PassRefPtrWebCore::DOMWindow, JSC::Structure*, WebCore::DOMWrapperWorld*) + 104
    18 QtWebKit 0x000000010068c748 WebCore::ScriptController::createWindowShell(WebCore::DOMWrapperWorld*) + 168
    19 QtWebKit 0x000000010068cf43 WebCore::ScriptController::initScript(WebCore::DOMWrapperWorld*) + 51
    20 QtWebKit 0x000000010068c94f WebCore::ScriptController::evaluateInWorld(WebCore::ScriptSourceCode const&, WebCore::DOMWrapperWorld*) + 159
    21 QtWebKit 0x000000010068cb89 WebCore::ScriptController::evaluate(WebCore::ScriptSourceCode const&) + 41
    22 QtWebKit 0x0000000100687ae3 WebCore::ScriptController::executeScript(WebCore::ScriptSourceCode const&) + 99
    23 QtWebKit 0x00000001005265d3 QWebFrameAdapter::evaluateJavaScript(QString const&) + 163
    24 QtWebKitWidgets 0x000000010049a2c2 QWebFrame::evaluateJavaScript(QString const&) + 18
    25 com.tubulatorapp 0x000000010011f2d0 ScriptInterface::runJSInDom(QString, QString) + 784 (ScriptInterface.cpp:54)@

    Any clues?

    1 Reply Last reply
    0
    • J Offline
      J Offline
      janfaroe
      wrote on last edited by
      #2

      Alrightie then. Since my case is rather specific (I need to evaluate a function call in a 3rd party JS chunk, and don't really care about the DOM as such - I just need the code to run), I ended up using QScriptEngine instead with a very sparse dummy DOM injected in the script engine instance, and then running the desired method.

      Not sure what the issue with QWebKit is here (threading?), but QScriptEngine works for me in this case.

      Others having the same issue (but needing a full DOM) might be interested in http://www.envjs.com, implementing a full DOM. The project https://qt.gitorious.org/qt-labs/qtscript-browser-env puts this in a Qt context as a QScriptEngine plugin, although the project is not compiling for Qt5.x. Should be easy to fix though.

      1 Reply Last reply
      0
      • B Offline
        B Offline
        brcontainer
        wrote on last edited by
        #3

        occurs only in debug mode?

        QT project: https://github.com/brcontainer/qt-helper

        1 Reply Last reply
        0
        • J Offline
          J Offline
          janfaroe
          wrote on last edited by
          #4

          In release as well.

          1 Reply Last reply
          0
          • B Offline
            B Offline
            brcontainer
            wrote on last edited by brcontainer
            #5

            I think the QWebFrame::setContent does not work well, it is equivalent to setHTML but is a little more advanced, so has no way to set the content of a page has loaded.

            The right thing would be this:

            QWebPage *page = ui->webview->page();
            QString scriptContent = "<scr" + "ipt>function HelloWorld() { alert&#40;'Hello World!!!'&#41;; }</sc" + "ript>";
            QByteArray injectScript = QString(scriptContent).toUtf8();
            
            page->mainFrame()->setContent(injectScript, "text/html");@
            

            But for your purpose this will not work, the right would you use another type of injection, such as the very "evaluateScript", like this:

            QString injectionJS = "(function() { var new = document.createElement('scr" + "ipt');";
            injectionJS +=  "new.inner" + "HTML = String((" + scriptContent + "));";
            injectionJS +=  "document.body.appendChild(new)";
            injectionJS +=  "});";
            
            page->mainFrame()->evaluateJavaScript(injectionJS);
            

            It's true

            Sounds like a bug. Please go to http://bugreports.qt-project.org/
            After create an issue, post your link here.

            Thanks!

            QT project: https://github.com/brcontainer/qt-helper

            1 Reply Last reply
            0
            • J Offline
              J Offline
              janfaroe
              wrote on last edited by
              #6

              Did it really crash on evaluating this?

              1 Reply Last reply
              0
              • B Offline
                B Offline
                brcontainer
                wrote on last edited by
                #7

                Not the evaluateScript that causes the "crash", but using the incorrect way QwebFrame::setContent. He apparently simulates the loading of a file, but if the page is already loaded it fails to load again.

                Same is not true-if the "crash" the QwebFrame::setContent would not work for what you want to do, because it would wipe the entire page and its original content would be lost.

                View this would be the proper way to work with QwebFrame::setContent does:

                @QwebFrame::setContent (QString("<scr"+"ipt>content</scr"+"ipt>").toUtf8()," text/html");@

                What I mean is that it seems that server to create a home page (as in Chrome have the "SpeedDial")


                For you to achieve your goal, I recommend doing something like this:

                https://gist.github.com/brcontainer/98016ee3655cfa535e8e (I fixed my example here)

                I tested, no crash using evaluateScript.

                QT project: https://github.com/brcontainer/qt-helper

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  janfaroe
                  wrote on last edited by
                  #8

                  Hm, the thing is, my approach works in most cases. The JS gets loaded and run. But when it meets certain injections (they are LARGE all of them - several MB of minified JS code), it crashes (as in the application dies, with a crash report and all, as in the one I've shown).

                  As you can see in the crash report, the culprit has to do with a string destructor after my call to QWebFrame::evaluateJavaScript(). For some reason I don't think it's related to the way the JS is loaded.

                  In any case, I'll try your approach at the earliest convenience; but for now QScript works for me.Thanks!

                  1 Reply Last reply
                  0
                  • B Offline
                    B Offline
                    brcontainer
                    wrote on last edited by
                    #9

                    Got it, then it is a limitation of reading time with the QtWebKit runtime.

                    Perhaps the process for files only work if the injection was asynchronous, but the QtWebKit does not support multiprocess (as is Chrome).

                    Why do not you do this:

                    1. Create um custom protocol in "QNetWorkAccessManager::createRequest", like "qrc:", eg. @janfaore://@

                    2. Save your Javascript in an file located in "User folder" (in Window c:\Users\USER_NAME\Local Datac\AppData\Local\project_user_data)

                    3. After save, inject saved file by your custom protocol, like this: @janfaore://myfile.js@

                    4. Set an interval/timeout before perform: @QWebFrame::evaluateScript("custom_function();");@

                    QNetWorkAccessManager example:

                    @QNetworkReply * netWork::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) {
                    const QString scheme = request.url().scheme().toLower().trimmed();
                    if ("janfaore" == scheme) {
                    return [YOUR CUSTOM QNetworkReply];
                    }

                    QNetWorkAccessManager::createRequest(op, request, outgoingData);
                    

                    }@

                    Note: Maybe need reimplement QNetWorkReply (create an custom QNetWorkReply).

                    QT project: https://github.com/brcontainer/qt-helper

                    1 Reply Last reply
                    0
                    • J Offline
                      J Offline
                      janfaroe
                      wrote on last edited by
                      #10

                      I appreciate your efforts in trying to help, but the problem is not loading the scripts (which are online resources that change regularly). I have no problem with this being asynchronous. The function I need to call via evaluateScript() is very, very simple and short (a few string manipulations), and a timeout in that context is very inlikely.

                      1 Reply Last reply
                      0
                      • B Offline
                        B Offline
                        brcontainer
                        wrote on last edited by
                        #11

                        Is that you said that major routes injected with "the evaluate" that caused the "crash", by this thought that if you create yourself a custom protocol like in "Firefox", you could throw huge scripts and the "Main Thread" (windows) would not crash.

                        Using "evaluateScript", you inject only this:

                        @< script src="janfaore://myfile.js"></ script >@

                        After use QTimer::singleShot() for evaluate your function.

                        QT project: https://github.com/brcontainer/qt-helper

                        1 Reply Last reply
                        0

                        • Login

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