[SOLVED] Apparently QMimeData* is responsible for it's own `delete` after having been used to set the clipboard.



  • Hey all,

    I'm creating a little application which is supposed to synchronize clipboards between different computers. Reading the clipboard goes well and so does transmitting but writing to a clipboard has given me a lot of trouble so far. The code is contained in a class which initializes QMimeData * mimeData in it's constructor and deallocates it in it's destructor, normal RAII stuff.

    I have tested this method with all lines related to mimeData commented out (and adding some simple integer and print operations to make sure that everything is indeed compiled and not optimized away). When the mimeData statements are added again the program fails. Valgrind mentions a lot of Invalid read of size 4/8 so I get the feeling that mimeData gets moved or overwritten but I have no idea how.

    I hope somebody can tell me what's going on,

    Thanks.

    @void ClipShareRunner::readFromSocket(QString str)
    {
    mimeData->clear();

    QByteArray strData = str.toLatin1();
    QJsonDocument strJsonDoc = QJsonDocument::fromJson(strData);

    QJsonObject strJsonObject = strJsonDoc.object();

    for(QString type : supportedTypes) {
    if(strJsonObject.contains(type)) {
    QByteArray data = strJsonObject[type].toString().toLatin1();
    mimeData->setData(type, data);
    }
    }

    clipboard->setMimeData(mimeData, QClipboard::Clipboard);
    }@

    I tried to add the remainder of the code but the forum kept complaining that it thought it was spam, so that didn't really work.



  • I had another go at solving the problem, allocating as much as possible on the heap and adding some debug statements:

    @void ClipShareRunner::readFromSocket(QString str)
    {
    qDebug() << "reading";
    mimeData->clear();

    qDebug() << "cleared mimedata";

    QByteArray strData = str.toLatin1();
    QJsonDocument strJsonDoc = QJsonDocument::fromJson(strData);

    QJsonObject strJsonObject = strJsonDoc.object();

    for(QString type : supportedTypes) {
    if(strJsonObject.contains(type)) {
    QByteArray data = strJsonObject[type].toString().toLatin1();
    mimeData->setData(type, data);
    }
    }

    qDebug() << "parsed json and added to mimedata";

    app->clipboard()->setMimeData(mimeData);

    qDebug() << "updated the apps clipboard";
    }@

    The last debug statement which is properly shown in valgrind is the second to last, which means that the error must be in:

    @app->clipboard()->setMimeData(mimeData);@
    app has been allocated on the heap in the main method. There is no delete so it should still be around.

    mimeData is a member of the encapsulating class, also on the heap without any delete statment.

    Lastly, what I found strange was that at first the program seems to run well, when transmitting data from machine 1 to machine 2 everything works great. However, once you start transmitting from machine 2 to machine 1 the program fails after parsing the JSON string.



  • Did some more testing, this time with the QtCreator debugger. For some reason the code which gives problems now is (at least that's where the yellow arrow next to the line number points to)

    @mimeData->clear()@

    which results in a pop up message:

    bq. The inferior stopped because it received a signal from the Operating System.
    Signal name : SIGBUS
    Signal meaning : Bus error



  • No matter what I do, the mimeData pointer keeps getting invalidated/moved/deleted by something causing either a (1) segfault (2) bus error (3) double free error. I've uploaded my dev repository, maybe someone spots something I've overlooked.

    "Repository":https://github.com/Gladdy/clipshare/tree/master/



  • After almost 2 days of debugging I found the problem:

    The system clipboard is not always in the same spot in memory with a constant pointer to it. It simply gets reallocated in a different place and the QMimeData* gets delete'd internally by the system or the Qt libraries.

    The solution is, every time you want to write to the clipboard, create a new QMimeData*, use that pointer for the QApplication::clipboard()->setMimeData(QMimeData*) function.

    It was somewhat strange creating a new QMimeData* without ever being responsible for the delete, but as it turns out (tested) it does not cause any major memory leaks (at least not for the content of the clipboard).

    It could have deduced from this part of documentation, but still ownership of the data does not háve to imply that you're also responsible for the cleanup.

    bq. Sets the clipboard data to src. Ownership of the data is transferred to the clipboard. If you want to remove the data either call clear() or call setMimeData() again with new data.


  • Moderators

    Hi, and welcome to the Qt Dev Net!

    I'm glad to hear you've found the solution.

    [quote author="Gladdyù" date="1422653004"]It could have deduced from this part of documentation, but still ownership of the data does not háve to imply that you're also responsible for the cleanup.

    bq. Sets the clipboard data to src. Ownership of the data is transferred to the clipboard. If you want to remove the data either call clear() or call setMimeData() again with new data.

    [/quote]With QObjects, that is exactly what it implies. See the "Object Trees & Ownership":http://doc.qt.io/qt-5/objecttrees.html article.

    In Qt, when Object X is said to take ownership of Object Y, or when it becomes the parent of Object Y, that means Object X is now responsible for deleting Object Y.

    In other words, a QObject only needs to be manually deleted if it doesn't have a parent.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.