diff options
author | João Abecasis <joao.abecasis@nokia.com> | 2012-01-30 14:50:04 +0100 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-02-07 09:47:51 +0100 |
commit | 5a92dd612472378ec329d380fdc8fe609478b06c (patch) | |
tree | 3f48a2970f9a0d7f81b09e3c91035a250ee0c05c /src/corelib/kernel/qmetatype.cpp | |
parent | b8cf1d6bdcaefaa610014a742808af3ab2c6fe06 (diff) |
Detect incompatibilities in repeated type registration
QMetaType used to register a typeName and factory functions for
creation/destruction of objects. While it would be possible for a single
type name to be registered matching different actual types and memory
layouts, there was little that could be done about it.
Now that QMetaType is tracking type information with a direct impact on
data layout and ABI (size and type flags) it is important that we check
and detect binary incompatibilities as early as possible.
[Such incompatibilities could arise from type name re-use (technically,
ODR violations) or, more commonly, as version mismatch between different
shared libraries or plugins.]
Only type size and flags are checked as function pointers to inline and
template or otherwise non-exported functions could trivially differ
across translation units and shared libraries.
When registering typedef types, a check is made to ensure the same name
doesn't get registered as different types.
Change-Id: I8211c3de75d4854ce8fafdb620d3a931c206e0c3
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@nokia.com>
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Diffstat (limited to 'src/corelib/kernel/qmetatype.cpp')
-rw-r--r-- | src/corelib/kernel/qmetatype.cpp | 66 |
1 files changed, 49 insertions, 17 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index b31bece376..a6b1599444 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -465,6 +465,8 @@ int QMetaType::registerType(const char *typeName, Deleter deleter, int idx = qMetaTypeStaticType(normalizedTypeName.constData(), normalizedTypeName.size()); + int previousSize = 0; + int previousFlags = 0; if (!idx) { QWriteLocker locker(customTypesLock()); idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), @@ -485,8 +487,33 @@ int QMetaType::registerType(const char *typeName, Deleter deleter, inf.flags = flags; idx = ct->size() + User; ct->append(inf); + return idx; } + + if (idx >= User) { + 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); } + if (previousFlags != flags) { + qFatal("QMetaType::registerType: Binary compatibility break " + "-- Type flags for type '%s' [%i] don't match. Previously " + "registered TypeFlags(0x%x), now registering TypeFlags(0x%x).", + normalizedTypeName.constData(), idx, previousFlags, int(flags)); + } + return idx; } @@ -510,25 +537,30 @@ int QMetaType::registerTypedef(const char* typeName, int aliasId) int idx = qMetaTypeStaticType(normalizedTypeName.constData(), normalizedTypeName.size()); - if (idx) { - Q_ASSERT(idx == aliasId); - return idx; - } - - QWriteLocker locker(customTypesLock()); - idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), - normalizedTypeName.size()); + if (!idx) { + QWriteLocker locker(customTypesLock()); + idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), + normalizedTypeName.size()); - if (idx) - return idx; + if (!idx) { + QCustomTypeInfo inf; + inf.typeName = normalizedTypeName; + inf.alias = aliasId; + inf.creator = 0; + inf.deleter = 0; + ct->append(inf); + return aliasId; + } + } - QCustomTypeInfo inf; - inf.typeName = normalizedTypeName; - inf.alias = aliasId; - inf.creator = 0; - inf.deleter = 0; - ct->append(inf); - return aliasId; + if (idx != aliasId) { + qFatal("QMetaType::registerTypedef: Binary compatibility break " + "-- Type name '%s' previously registered as typedef of '%s' [%i], " + "now registering as typedef of '%s' [%i].", + normalizedTypeName.constData(), QMetaType::typeName(idx), idx, + QMetaType::typeName(aliasId), aliasId); + } + return idx; } /*! |