property.write corrupts Object



  • Hi,
    when writing a property foo to an object, property bar is corrupted. This method works hundreds of times in my program, but there is one occasion where it always fails. I can't see what I do different there, but it is reproducible. However, the kind how it fails makes me scratching my head:

    virtual void setProperty(const QSharedPointer<Entity> &e,QSharedPointer<Entity> &value, const QMetaProperty &property)  override {
            QSharedPointer<RatingMarkSystem> en = *reinterpret_cast<QSharedPointer<RatingMarkSystem>*>(&value);
            QVariant var;
            var.setValue<QSharedPointer<RatingMarkSystem>>(en);
    
            // all is well here
            if (QString(e->metaObject()->className())==QString("RatingMarkIncident")) {
                auto rms = e->property(QString("ratingMarkSystem").toStdString().c_str()).value<QSharedPointer<RatingMarkSystem>>();
                if (rms) {
                    qDebug()<<rms->name();
                }
                qDebug()<<e->property(QString("symbol").toStdString().c_str()).toString();
            }
    
            qDebug()<<"property.name(): "<<property.name();
            // the actual writing
            property.write(e.data(), var);
            Q_ASSERT(e->property(property.name()) == var);
    
            // the property itself seems ok (it actually isn't, fails later when used more intensively)
            if (QString(e->metaObject()->className())==QString("RatingMarkIncident")) {
                auto rms = e->property(QString("ratingMarkSystem").toStdString().c_str()).value<QSharedPointer<RatingMarkSystem>>();
                if (rms) {
                    qDebug()<<rms->name();
                }
                // HERE is the crashing line:
                qDebug()<<e->property(QString("symbol").toStdString().c_str()).toString();
            }
        }
    
    

    Please note, that RatingMarkSystem and RatingMarkIncident both derive from Entity, which itself derives from QObject.

    The output is (reproducibly):

    "15 bis 0 Punkte als 1+ bis 6"
    "2"
    property.name(): ratingMarkSystem
    "15 bis 0 Punkte als 1+ bis 6"
    ASSERT: "!m_thread.isRunning()" in file qqmldebugserver.cpp, line 655

    I've been hunting this for months. I don't have any idea what might happen here or where to start looking for a possible solution. Please note, that the code normally runs perfectly. It's just one situation where it always fails in this peculiar fashion.
    Any ideas?


  • Moderators

    Well since you are hunting this for months, I don't hope to magically help you in a single post :-) But I'll try throwing some ideas, maybe they will have some effect. We'll see.

    1. A bit unrelated, but: why waste CPU and RAM to create QString, then convert it to STD, then to C, when you can simply do: e->property("ratingMarkSystem")? (actually, perhaps using QStringLiteral would be a better idea). Or, if you have these names stored in a QString or QLatin1String: e->property(qPrintable(someString))

    2. The assert line which fails is very weird. Does the crash also happen in release mode? Are you trying to access objects from a different thread by any chance? Are you sure the crash happens here, and not in some other part of the program?

    3. Is there any signal-slot connection which updates "symbol" property after "ratingMarkSystem" is changed? Or when the old rms is destroyed?

    4. What do you mean by "the property itself seems ok (it actually isn't, fails later when used more intensively)" - the ratingMarkSystem property? If yes, that that issue has to be fixed first and it should resolve the problem with "symbol", too, I think. I suspect a problem with QSharedPointer being converted/ cast, but I don't have any specific hint or accusation here. You may try if switching to raw pointers helps. And you can verify if QSharedPointer<RatingMarkSystem> is registered with metatype system.



  • @sierdzio
    Thanks for answering! The chance to help is not too faint, as I am a self-taught noob ;-)

    1. Proof of the above :) It was sheer despair, I'd had it like in your first proposal, changed it while debugging to be dead sure.
    2. The error is actually a "Runtime Error", the assert in qqmldebugserver is endemic to debugging, in fact. Sorry for misleadingly add it in the post. Please note that the Q_ASSERT in the code has never failed. No other threads are involved (haven't used any threading in my life yet). The crash happens exactly here. Before the write, everything is - or seems - fine.
    3. There is no signal attached.
    4. I have researched that in more depth now by recursively browsing and debug-printing through all of its properties. That works well with the value before writing it to the property, it does not work with the newly written property ratingMarkSystem, because: it is surprisingly lacking a StaticMetaObject! In spite of working many times before when writing such a value to such a property... To be precise: when entering my Entity::dumpProperties() method, the "this" pointer's staticMetaObject is <not accessible> [0] in the debugger, all its base classes' staticMetaObjects are still there and probably functioning.

    As for the QSharedPointer: Because the whole program (many thousands of lines) is bases on this concept, it is not easily doable to change that here. It is definitely a last resort thing. I've had a closer look into the conversion again, though.
    I've changed the reinterpret_cast to...

    QSharedPointer<RatingMarkSystem> en = value.objectCast<RatingMarkSystem>();
    

    ...to no avail. The MetaType registration is done with...

    qRegisterMetaType<QList<QSharedPointer<T>>>(lName.toLatin1().constData());
    

    ...and I've now - just for trying it out - additionally put...

    Q_DECLARE_METATYPE(QSharedPointer<RatingMarkSystem>)
    

    ...in, but still no luck :-(

    If it was just for the ratingMarkSystem to break, I'd quietly keep on searching for a problem within it. But how is it possible that a MetaObject breaks? An how can an apparently unrelated QString property be affected by that? This goes beyond my head.

    QVariant symvar = e->property("symbol");
    

    is - like the RMS' staticMetaObject - "not accessible" in the gdb debugger after property.write.

    How can writing one property corrupt another one?


  • Moderators

    @SeDi said in property.write corrupts Object:

    when writing a property foo to an object, property bar is corrupted.

    This sounds like memory corruption. There are many possible causes, such as interpreting pointers wrongly, using uninitialized/dangling pointers, writing out-of-bounds to a raw C array, etc.

    It is possible that the corruption occurs outside of your setProperty() function. The line that crashes might not be related to the problem at all.

    it is reproducible

    Does it fail the same way in both Debug mode and Release mode?

    @SeDi said in property.write corrupts Object:

    I've changed the reinterpret_cast to...

    QSharedPointer<RatingMarkSystem> en = value.objectCast<RatingMarkSystem>();
    

    ...to no avail.

    What do you mean, "to no avail"? Do you mean the same error occurs? Do you mean the code doesn't compile? Or something else?

    Anyway, objectCast() is definitely a lot safer than reinterpret_cast. Do you do casts anywhere else in your code?

    Just to be sure: at the very start of your setProperty() function, call qDebug() << value->metaObject()->className(); Does it print "RatingMarkSystem"?


  • Lifetime Qt Champion

    Hi,

    If I have followed correctly the variant your get contains a QSharedPointer to an object of your custom type and you try to call toString on that ? Are you implementing the corresponding conversion operator ?

    What happens if you remove the toString in your qDebug line ?

    On a side note, if you are expecting to send objects from your classes to qDebug fairly often, I'd recommend writing the corresponding stream operator so you known exactly what you send to it.

    Also, to make your code easier to write and read, you should consider type alias or the good old typedef.



  • @JKSH
    Thank you for time & effort! It fails in absolutely the same manner in Release & Debug mode. Changing the cast to the safer one didn't change anything in the behavior, but I will review all my casts and change it wherever possible, just to be on the safe(r) side. Sorry for having been imprecise here.

    qDebug() << value->metaObject()->className(); prints "RatingMarkSystem" until the property.write. After that, the same line interestingly fails in the same manner as when I read out the property from the entity and then call its MetaObject. It's not too surprising, as we set an object pointer to the entity's property, so we refer to the very same instance.

    I acknowledge the possibility of some memory corruption earlier in the code, but I can't, for the life of me, bring the value object to a crash before property.write is done. I don't know how to prove its integrity or, more logically correct, find any hidden corruption - if there is one. And still, writing a QSharedPointer<something> property to an object should not make its QString property "not accessible", whatever flaws the object pointed to might have...

    I have stumbled over this QTBUG 40644 - do you think this could be related?

    I am still feeling puzzled and clueless, I'm afraid. But I am very thankful for your help, guys, as you are indeed pointing me into corners and aspects I haven't yet had in focus yet.



  • @SGaist
    Thank you for your answer! Those are two different properties. The .toString() is used on symbol, a QString property, I have not implemented any conversion operator for it.
    Omitting the toString actually means dealing with a variant:

    QVariant symvar = e->property("symbol");
    qDebug() << "still gets printed";
    qDebug() << symvar; // crashes here (when placed after property.write)
    qDebug() << "never reached";
    

    Regarding type alias: that does look very interesting! Thank you very much for helping, although unfortunately the problem is still unresolved :-(


  • Moderators

    @SeDi said in property.write corrupts Object:

    It fails in absolutely the same manner in Release & Debug mode.

    This makes it a little bit less likely to be a memory corruption issue, but I can't say for sure.

    Changing the cast to the safer one didn't change anything in the behavior, but I will review all my casts and change it wherever possible, just to be on the safe(r) side. Sorry for having been imprecise here.

    No worries.

    It's always a good idea to use safe practices -- this helps us to find errors faster.

    qDebug() << value->metaObject()->className(); prints "RatingMarkSystem" until the property.write. After that, the same line interestingly fails in the same manner as when I read out the property from the entity and then call its MetaObject. It's not too surprising, as we set an object pointer to the entity's property, so we refer to the very same instance.

    I acknowledge the possibility of some memory corruption earlier in the code, but I can't, for the life of me, bring the value object to a crash before property.write is done. I don't know how to prove its integrity or, more logically correct, find any hidden corruption - if there is one.

    I can't really think of anything either, sorry...

    Some other things you could try:

    • See if the same crash happens on a different OS
    • If you have a *nix machine, see if Valgrind finds any errors
    • See if the same crash happens using a different compiler (you'd need to download a new version of Qt)
    • Make a copy of your project, and gradually remove unrelated code until the crash disappears. This could help you narrow down the cause of the crash.

    Also, does your debugger produce a stack trace when it crashes?

    And still, writing a QSharedPointer<something> property to an object should not make its QString property "not accessible", whatever flaws the object pointed to might have...

    It could, if the problem is a memory corruption.

    I have stumbled over this QTBUG 40644 - do you think this could be related?

    It's possible. It don't think it's trivial to check, though.

    I am still feeling puzzled and clueless, I'm afraid. But I am very thankful for your help, guys, as you are indeed pointing me into corners and aspects I haven't yet had in focus yet.

    You are in good company. Google for "debugging horror stories"


  • Lifetime Qt Champion

    Does it also happen if you:

    1. Create your object
    2. Put it in a QSharedPointer
    3. Set that pointer in a QVariant
    4. Print the QVariant through qDebug

    ?



  • Folks, thank you all! With all your help I was finally able to find the mistake, which happened to be inside my code (not surprisingly). It turned out that, under a certain condition, I was writing an object of a wrong type into a 'list of objects' property. That didn't produce any problems at that point and thus went unnoticed for quite a long time. You haven't made my day, you've made my year. Thank you!


Log in to reply
 

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