Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Qt Creator debugger watch <not accessible>?



  • I have a function:

    bool clsMsgSender::blnAnythingToDo(QJsonObject& robjJSON) {
        QMutexLocker lock(&mMutex);
        QTcpSocket::SocketState sckState = mpsckClient->state();
    
        if ( sckState != QAbstractSocket::ConnectedState ) {
        //Not connected yet, ensure JSON is emptyf
            memset(&robjJSON, 0, sizeof(robjJSON));
        } else {        
        //Check if there is anything waiting in the send later
            if ( clsModule::blnSendLater(robjJSON) != true ) {
        //Anything waiting to send as soon as connection is established?
                if ( mqueMsgsOut.isEmpty() != true ) {
                    robjJSON = mqueMsgsOut.dequeue();
                }
            }
        }
        return (robjJSON.isEmpty() != true);
    }
    

    I can see that the reference passed to the QJsonObject is populated in the function but when I step of of the call:

            if ( blnAnythingToDo(objJSON) != true ) {
        //Nothing to do...yet!
                continue;
            }
    

    The debugger is showing objJSON <not accessible> which is a local variable, why? This is very frustrating.



  • @SPlatten said in Qt Creator debugger watch <not accessible>?:

    Don't know.

    But:

    memset(&robjJSON, 0, sizeof(robjJSON));

    Are you really supposed to do this??? We're not in C here, where did you get this idea from...?



  • @JonB , simply experience, there is nothing wrong with it...is there?


  • Moderators

    @SPlatten said in Qt Creator debugger watch <not accessible>?:

    simply experience, there is nothing wrong with it...is there?

    The 'experience' is (very) wrong. You assume a specific memory layout, which isn't how this is implemented. Fix this pronto! And a piece of advice: don't assume something is implemented a specific way, unless you like pain and suffering.



  • @SPlatten said in Qt Creator debugger watch <not accessible>?:

    simply experience, there is nothing wrong with it...is there?

    Please don't do this with a C++ compiler. It works only is you are initializing a POD (Plain Old Data) type, but not with C++ class or struct!

    You can do this with ANSI-C compiler, but don't do this with C++ compiler.

    ==> https://stackoverflow.com/a/2481662



  • @KroMignon , Fair enough, I've cleaned up the application and will take the advice onboard.


  • Moderators

    @KroMignon said in Qt Creator debugger watch <not accessible>?:

    Please don't do this with a C++ compiler.

    This isn't about the compiler.

    It works only is you are initializing a POD (Plain Old Data) type,

    This is correct.

    but not with C++ class or struct!

    This is incorrect. There's no "C++ class or struct" as such. C++ can have POD, and C-style initialization works for that too. It works also for classes with methods, where the memory layout is known and well defined (i.e. ones that don't have virtual methods). The main error here is the assumption, not the syntax or the language itself.



  • @kshegunov , I use structs simply for defining a data layout, I don't use structs like classes, I prefer to stick with classes for that. I take your point though but for me its safe to use mem... functions with structures.


  • Moderators

    @SPlatten said in Qt Creator debugger watch <not accessible>?:

    I use structs simply for defining a data layout, I don't use structs like classes, I prefer to stick with classes for that. I take your point though but for me its safe to use mem... functions with structures.

    No, it's not unless you know exactly how that struct is declared and what the data members are supposed to do. In your case here, the piece of code is technically correct. It's going to zero out the memory of the json object, however the nullptrs you get as data members are wrong, as the methods and functions which work with said data are not expecting that. You can make the same mistake with a struct in a C code, doing the same idea and tripping over the same wires.

    struct A
    {
        void * blob;
    };
    
    void init_a(A * obj)
    {
        // Allocate memory and prepare the blob
    }
    
    void use_a(A * obj)
    {
        // Work with blob assuming that `init_a` was called
        // If we haven't called `init_a` or if we have set `A::blob` to 0 then this may just as well segfault
    }
    

    As I said, this is not about the language, it isn't about the structure or syntax. It's about the meaning - the semantics. You're assuming specific semantics of the data members, which isn't true generally ... and also specifically in this case ...



  • @kshegunov , I'm not sure I follow where you are going with this. If I have a structure, e.g:

    struct A {
        void* ptr;
        int a;
        double b;
        char c;
    }
    

    The memory layout for a 32 bit system base address of an instance structure type A, ptr will point to the base address and the ptr is 4 bytes long after that the integer will occupy the next 4 bytes, the double will occupy the next 8 bytes lastly the character will occupy 1 byte. This will be contiguous according to the size of each type in the structure. memset on the structure will 0 all members of the structure.



  • @SPlatten
    This might be OK on your own structs. But QJsonObject is not yours. You don't know how it's implemented. It's not just the layout and possibly the vtable. It will have a constructor. You assume it would like to be all zeroes because it's "empty", but the constructor may actually initialize all sorts of things not to be 0.


  • Moderators

    @SPlatten said in Qt Creator debugger watch <not accessible>?:

    The memory layout for a 32 bit system base address of an instance structure type A, ptr will point to the base address and the ptr is 4 bytes long after that the integer will occupy the next 4 bytes, the double will occupy the next 8 bytes lastly the character will occupy 1 byte. This will be contiguous according to the size of each type in the structure.

    Actually it doesn't work exactly like that because there's padding and/or alignment the compiler may decide to do, but that's beside the point.

    memset on the structure will 0 all members of the structure.

    Yes, and the function working on the structure that expects the said pointer to contain a valid address to a memory block just crashes - what I've illustrated in my example. You'd assumed that methods of a class (which is equivalent to functions taking a reference to a structure as first parameters) are going to handle zero-ed out members, especially if you take into account you're not the one that'd written the functions/methods/structure/class. Usually they won't handle such cases, because you're supposed to abide by the contract the API is. RAII isn't a concept specific to C++, it's a concept that applies to C as well, it's just the recommended way for C++.

    PS.
    Think about it like this: "Empty" is not the same as "zeroed out".


Log in to reply