Results 1 to 4 of 4

Thread: Custom Datatypes Causing Undefined Behavior Among Global Variable References

  1. #1

    Default Custom Datatypes Causing Undefined Behavior Among Global Variable References

    To give you a background, I have developed in C (and some C++ when it's called for) for the past several years, along with x86 assembly (inline and standalone). I am new to Qt and am using QT Creator 5.1 with MinGW compiler (Windows XP/no ASLR). My problem, in summary, is that I cannot use a global variable across different namespaces, as somehow the memory changes its location, even if dynamically allocated. I have tested this problem on another platform (VC++ and Linux/Clang) without using Qt and it works just fine.



    The best way I can describe this problem is whenever I am using a user-defined datatype (struct serverUpdateInformation_t) within a namespace (NS_A) function, if I use a different variable of the same type (struct serverUpdateInformation_t) within a namespace (NS_B) which calls NS_A earlier in program flow, the offsets/fields within my struct change. Even using pre-processing directives like #pragma pack... do not work in keeping data uniform within memory.

    Needless to say it is frustrating. I am trying to have just one copy of my variable available between "compilation units", but after trying several tricks the best I can get is the variable to have its memory address changed between functions, even though there is no explicit reassignment of the pointer location.

    As an aside, these functions are not being compiled with the Q_OBJECT macro in their respective header files. I'm just trying to do "standard" C++, if not standard C. However, other "compilation units" are using the Q_OBJECT macro, which does end up calling some of these functions via my GUI code.

    Example:

    Assume variable "static serverLoginResponse_t serverLoginResponse" is defined within a "GlobalVARS.h" header file among two or more namespaces with functions which access the same variable.

    Qt Code:
    1. namespace NS_A
    2. {
    3. ...
    4. int NS_A::RecvUpdateInformation()
    5. {
    6. // Whenever I try to use the global variable "serverLoginResponse" directly in NS_A::FuncA, if I try to again use it in NS_A::FuncB or NS_B::FuncA, the compiler makes
    7. // another "copy" of the static global variable, thus negating the point of a global variable.
    8. // Thus, I use a pointer, which at least lets me keep the global variable in the same place in memory.
    9. Credentials::serverUpdateInformation_t* pServerUpdateInformation = &Credentials::serverUpdateInformation;
    10. ...
    11. // I allocate and setup fields below for a function in namespace NS_B to deal with...
    12. return status;
    13. }
    To copy to clipboard, switch view to plain text mode 

    The interesting thing is, when I try to achieve the same reference in an NS_B function, it alters the offsets of the struct fields in NS_A. Yes, I know! It will still compile fine, yet the offsets of the struct's fields change between "compilation units".

    For example, if I use this following code in NS_B

    Qt Code:
    1. namespace NS_B
    2. {
    3. ...
    4. int Login()
    5. {
    6. ...
    7. // If we don't uncomment the following line(s), our offsets in referencing the struct get messed up, leading to improper computation.
    8. Credentials::serverUpdateInformation_t* pServerUpdateInformation = &Credentials::serverUpdateInformation;
    9. Credentials::serverUpdateInformation serverUpdateInformation_LocalCopy = Credentials::serverUpdateInformation; // This line will cause offset problems as well, as an example.
    10. ...
    11. return status;
    12. }
    13. }
    To copy to clipboard, switch view to plain text mode 



    This has been frustrating beyond belief. I know this is possible in standard C without any problems. It feels like I'm fighting against the framework in order to do basic low-level C/C++ within QT.
    My current workaround solution was to serialize this datatype into a file after I initially referenced it in the NS_A function. Sadly, whenever I introduce a local variable of the same datatype within a different "compilation unit", it affects the memory layout of the global variable of the same type, even though they both should not interfere with each other!

    Please help!

  2. #2
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Custom Datatypes Causing Undefined Behavior Among Global Variable References

    The in-memory layout of a structure under C/C++ is controlled by the declaration and choices made by the compiler and has nothing at all to do with Qt. If your two separate compilation units are accessing the internals of a struct differently then either they were given different declarations from which to work, or they were built with different compiler options (e.g. affecting packing or alignment).

    However, I think your problem is not with internal packing of structure but simply with multiple instance of the structure. You say we should assume a static global is defined in a header. Every place this header is included in a CPP file will create a separate instance of that variable: the values in these instances are independent and pointers to them will be different. The header should be written:
    Qt Code:
    1. namespace Credentials {
    2.  
    3. struct serverUpdateInformation_t {
    4. // stuff
    5. };
    6.  
    7. // This tells the C++ compiler the variable exists somewhere
    8. extern serverUpdateInformation_t serverUpdateInformation;
    9.  
    10. }
    To copy to clipboard, switch view to plain text mode 
    and in ONE cpp file:
    Qt Code:
    1. #include "header.h"
    2. // This is where the storage actually is and the linker will find it
    3. Credentials::serverUpdateInformation_t serverUpdateInformation;
    To copy to clipboard, switch view to plain text mode 

  3. #3

    Default Re: Custom Datatypes Causing Undefined Behavior Among Global Variable References

    Thank you for the response Chris.

    However, even after changing "static" to "extern" and declaring within the .cpp file globally, accessing the variable either through reference or direct, will modify the program execution and data received from my server.

    If need be, I can upload the .cpp and .h files. However, I'll copy and paste the snippets below:


    Credentials.h
    Qt Code:
    1. #ifndef CREDENTIALSTYPES_H
    2. #include "CredentialsTypes.h"
    3. #endif
    4.  
    5. namespace Credentials
    6. {
    7. static loginSend_t loginSend; // #1
    8. static serverLoginResponse_t serverLoginResponse; // #2
    9. static clientVersion_t clientVersion; // #3
    10. extern serverUpdateInformation_t serverUpdateInformation; // #4
    11.  
    12. ...
    To copy to clipboard, switch view to plain text mode 


    Credentials.cpp
    Qt Code:
    1. namespace Credentials
    2. {
    3. serverUpdateInformation_t serverUpdateInformation;
    4.  
    5. int Login()
    6. {
    7. // Establish a new ServerSession().
    8. QString dns = QLatin1String("login.xpextend.com");
    9. QString ipString = QLatin1String("192.168.56.102");
    10. QStringList ipNotation(ipString.split(QLatin1String(".")));
    11. quint32 ipAddress;
    12.  
    13. Credentials::serverUpdateInformation_t* pServerUpdateInformation = &Credentials::serverUpdateInformation;
    14. // [B]Leaving in the above line, as you'll see below, ANYWHERE in this compilation unit will affect the ability of the QByteArray to receive information from the server[/B]
    15.  
    16. ipAddress = ((ipNotation.at(0).toLong()) << 24) | ((ipNotation.at(1).toLong()) << 16) |
    17. ((ipNotation.at(2).toLong()) << 8) | ((ipNotation.at(3).toLong()) << 0);
    18. ServerSession s(ipString);
    19.  
    20. if (s.Connect() == ERROR_SUCCESS)
    21. {
    22. // Successfully connected. Client successfully sent the whole loginResponse_t structure to the server.
    23. // Now we must read the serverLoginResponse_t structure.
    24. int loginResponse = s.ParseLoginResponse();
    25.  
    26. if (loginResponse == ERROR_SUCCESS)
    27. {
    28. // Goal: Determine if we need to download any new patches or client.
    29.  
    30. // Attempt to send the server our version number.
    31. if (s.SendVersionNumber() != ERROR_SUCCESS)
    32. {
    33. // There was an error sending our version number.
    34. }
    35.  
    36. // Attempt to read the server's update information.
    37. if (s.RecvUpdateInformation() != ERROR_SUCCESS)
    38. {
    39. // There was an error receiving update information.
    40. }
    41.  
    42. // At this point we can parse the structure the serverUpdateInformation_t
    43. //Credentials::serverUpdateInformation_t* pServerUpdateInformation = &Credentials::serverUpdateInformation;
    44. // [B]Why does the above ^^^ and/or below screw up ServerSession's variable in the call to s.RecvUpdateInformation()?[/B]
    45. //Credentials::serverUpdateInformation_t serverUpdateInformation_Copy = Credentials::serverUpdateInformation;
    46.  
    47. // Check to see if we need to update our client or not.
    48. if (CURRENT_VERSION < clientUpdate.version)
    49. ...
    To copy to clipboard, switch view to plain text mode 



    ServerSession.cpp
    Qt Code:
    1. ...
    2. int ServerSession::RecvUpdateInformation()
    3. {
    4. // Check to make sure the socket is currently connected.
    5. if (this->tcpSocket->ConnectedState == QAbstractSocket::ConnectedState)
    6. {
    7. // Populate magic values for PATCH_UPDATE_t and CLIENT_UPDATE_t.
    8. snprintf(Credentials::serverUpdateInformation.patchUpdate.magic, strlen(PATCH_UPDATE_MAGIC), "%s", PATCH_UPDATE_MAGIC);
    9. snprintf(Credentials::serverUpdateInformation.clientUpdate.magic, strlen(CLIENT_UPDATE_MAGIC), "%s", CLIENT_UPDATE_MAGIC);
    10.  
    11. QByteArray inputArray;
    12. char* contents;
    13. int indexContents = 0;
    14.  
    15. while (!inputArray.contains(END_UPDATE_MAGIC))
    16. {
    17. this->tcpSocket->waitForReadyRead();
    18. inputArray += this->tcpSocket->readAll();
    19. }
    20.  
    21. contents = inputArray.data(); /* Pointer to data including NULL byte */
    22. // "contents" is free()'d when QByteArray goes out of scope.
    23.  
    24. // Populate Credentials::serverUpdateInformation.
    25. Credentials::serverUpdateInformation_t* pServerUpdateInformation = &Credentials::serverUpdateInformation;
    26. memcpy(pServerUpdateInformation, contents, sizeof(Credentials::serverUpdateInformation.patchUpdate) -
    27. sizeof(Credentials::serverUpdateInformation.patchUpdate.lists));
    28. indexContents += sizeof(Credentials::serverUpdateInformation.patchUpdate) -
    29. sizeof(Credentials::serverUpdateInformation.patchUpdate.lists);
    30. ...
    To copy to clipboard, switch view to plain text mode 



    Basically, if I create or try to reference ANY variable of type serverUpdateInformation_t within Credentials::Login() it will effect the (QByteArray) inputArray receiving data from the server. Depending on where in Credentials::Login() I declare a variable of type serverUpdateInformation_t I have seen it lead to no socket data being read or socket data being interpreted incorrectly by the QByteArray data type, which expects the size of the QByteArray as the first qint16 (WORD) of data sent.

    Why would declaring, for example, a completely-unrelated variable of type serverUpdateInformation_t affect what is going on within a different compilation unit, especially AFTER the function has been called before a declaration is made?!!!

  4. #4
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Custom Datatypes Causing Undefined Behavior Among Global Variable References

    It doesn't. The only ways this can occur are outlined in my first paragraph or the result of programmer error (e.g. overrunning a buffer accessed through a pointer). Do a complete rebuild and take the allocation of storage space out of the header.

    If your problem persists you need to provide a small, complete, compilable example that demonstrates the problem.

Similar Threads

  1. Repeater and itemAt undefined references
    By porterneon in forum Qt Quick
    Replies: 1
    Last Post: 21st September 2011, 15:32
  2. undefined references to mysql
    By Ahas in forum Installation and Deployment
    Replies: 3
    Last Post: 25th May 2011, 18:02
  3. Replies: 0
    Last Post: 19th November 2009, 19:02
  4. QWebView undefined references
    By xtreme in forum Qt Programming
    Replies: 2
    Last Post: 28th July 2008, 08:08
  5. Replies: 2
    Last Post: 12th December 2007, 13:15

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.