Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-35935

Q_DECLARE_METATYPE may fail to work properly when loading meta-type components from DLLs since the symbols "creator", "deleter", "constructor" and "destructor" are not updated in adjacent calls.

    XMLWordPrintable

Details

    • Bug
    • Resolution: Out of scope
    • Not Evaluated
    • None
    • 5.2.0
    • None
    • Windows OS (Win7, 32/64 Bit, Win8 32/64 Bit), Visual Studio 2012, tested QT 5.1.2 and QT 5.2. Problem arised when using Qwt but problem is definitely related to QT and not QWT. Bugfix proposed here solved the problem for me.

    Description

      The problem is related to loading a class declared as a metatype by
      using the Q_DECLARE_METATYPE macro from a dll.
      When first loading the dll, the Q_DECLARE_METATYPE macro initiates a call to function QMetaType::registerNormalizedType
      in file qmetatype.cpp where the type as well as the symbols creator, deleter, constructor and destructor are registered.

      When now unloading and reloading the dll, the symbols for the callbacks creator, deleter, constructor and destructor should be updated in function QMetaType::registerNormalizedType in file qmetatype.cpp
      since the addresses of creator, deleter, constructor and destructor may have changed. This does not happen since it is detected that the type has been registered before.

      If the symbols are not updated, the old symbols may be used as a target to a callback which point to invalid
      memory segments which leads to a crash of the application.

      Note: In an application with multiple dlls loaded at runtime, the symbols form the first time loading the dll may be identical
      to the symbols for the 4 callbacks if all dlls are loaded in identical order. the described crash happen only if
      the dlls are loaded in a different order compared toi the first time. Therefore, this does not happen all the time.

      And here is my fix to function QMetaType::registerNormalizedType
      in file qmetatype.cpp which prevents my application from crashing
      (modification NEW CODE vs OLD CODE):

          int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, Deleter deleter,
          Creator creator,
          Destructor destructor,
          Constructor constructor,
          int size, TypeFlags flags, const QMetaObject *metaObject)
          {
          QVector<QCustomTypeInfo> *ct = customTypes();
          if (!ct || normalizedTypeName.isEmpty() || !deleter || !creator || !destructor || !constructor)
          return -1;
           
          int idx = qMetaTypeStaticType(normalizedTypeName.constData(),
          normalizedTypeName.size());
           
          int previousSize = 0;
          int previousFlags = 0;
          if (idx == UnknownType) {
          QWriteLocker locker(customTypesLock());
          idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(),
          normalizedTypeName.size());
          if (idx == UnknownType) {
          QCustomTypeInfo inf;
          inf.typeName = normalizedTypeName;
          inf.creator = creator;
          inf.deleter = deleter;
          #ifndef QT_NO_DATASTREAM
          inf.loadOp = 0;
          inf.saveOp = 0;
          #endif
          inf.alias = -1;
          inf.constructor = constructor;
          inf.destructor = destructor;
          inf.size = size;
          inf.flags = flags;
          inf.metaObject = metaObject;
          idx = ct->size() + User;
          ct->append(inf);
          return idx;
          }
           
          if (idx >= User) {
           
          /* NEW CODE */	
          QCustomTypeInfo ttt = ct->at(idx - User);
          previousSize = ttt.size;
          previousFlags = ttt.flags;
          ttt.creator = creator;
          ttt.deleter = deleter;
          ttt.constructor = constructor;
          ttt.destructor = destructor;
          ct->replace(idx - User, ttt);[/B]
          /* OLD CODE
           
            previousSize = ct->at(idx - User).size;
            previousFlags = ct->at(idx - User).flags;
          */
          }
          }
           
          if (idx < User) {
          previousSize = QMetaType::sizeOf(idx);
          previousFlags = QMetaType::typeFlags(idx);
          }
           
          if (previousSize != size) {
          qFatal("QMetaType::registerType: Binary compatibility break "
          "-- Size mismatch for type '%s' [%i]. Previously registered "
          "size %i, now registering size %i.",
          normalizedTypeName.constData(), idx, previousSize, size);
          }
           
          // Ignore WasDeclaredAsMetaType inconsitency, to many users were hitting the problem
          previousFlags |= WasDeclaredAsMetaType;
          flags |= WasDeclaredAsMetaType;
           
          if (previousFlags != flags) {
          const int maskForTypeInfo = NeedsConstruction | NeedsDestruction | MovableType;
          const char *msg = "QMetaType::registerType: Binary compatibility break. "
          "\nType flags for type '%s' [%i] don't match. Previously "
          "registered TypeFlags(0x%x), now registering TypeFlags(0x%x). "
          "This is an ODR break, which means that your application depends on a C++ undefined behavior."
          "\nHint: %s";
          QT_PREPEND_NAMESPACE(QByteArray) hint;
          if ((previousFlags & maskForTypeInfo) != (flags & maskForTypeInfo)) {
          hint += "\nIt seems that the type was registered at least twice in a different translation units, "
          "but Q_DECLARE_TYPEINFO is not visible from all the translations unit or different flags were used."
          "Remember that Q_DECLARE_TYPEINFO should be declared before QMetaType registration, "
          "preferably it should be placed just after the type declaration and before Q_DECLARE_METATYPE";
          }
          qFatal(msg, normalizedTypeName.constData(), idx, previousFlags, int(flags), hint.constData());
          }
           
          return idx;
          }
      

      Note: More info is available here:

      http://www.qtcentre.org/threads/57367-Is-this-a-bug

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            thiago Thiago Macieira
            hkhauke Hauke Krüger
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes