From 813af5f0655c332b2853d156b91c5265b85cbc70 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 3 Jul 2014 13:38:59 +0200 Subject: Remove QHashDummyNode and avoid undifined behavior A lot of code in QHash is doing casting to QHashNode while the pointer may be of type QHashDummyNode. This is a lot of undefined behavior. Remove QHashDummyNode and specialize QHashNode for QHashDummyValue instead. QHashDummyValue is the only type for which QTypeInfo::isDummy is true. Q_DUMMY and QTypeInfo::isDummy are internal API, so is QHashDummyNode, so we can remove them. Task-number: QTBUG-40029 Change-Id: I60c2ff0933075b9202bde89a9992746052f75133 Reviewed-by: Thiago Macieira --- src/corelib/tools/qhash.h | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 1d76a2b3d1..db2d084035 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -217,17 +217,23 @@ private: Q_DISABLE_COPY(QHashNode) }; -template -struct QHashDummyNode +// Specialize for QHashDummyValue in order to save some memory +template +struct QHashNode { - QHashNode *next; + union { + QHashNode *next; + QHashDummyValue value; + }; const uint h; const Key key; - inline QHashDummyNode(const Key &key0, uint hash, QHashNode *n) : next(n), h(hash), key(key0) {} + inline QHashNode(const Key &key0, const QHashDummyValue &, uint hash, QHashNode *n) + : next(n), h(hash), key(key0) {} + inline bool same_key(uint h0, const Key &key0) const { return h0 == h && key0 == key; } private: - Q_DISABLE_COPY(QHashDummyNode) + Q_DISABLE_COPY(QHashNode) }; @@ -276,7 +282,6 @@ Q_HASH_DECLARE_INT_NODES(uint); template class QHash { - typedef QHashDummyNode DummyNode; typedef QHashNode Node; union { @@ -289,7 +294,6 @@ class QHash } static inline int alignOfNode() { return qMax(sizeof(void*), Q_ALIGNOF(Node)); } - static inline int alignOfDummyNode() { return qMax(sizeof(void*), Q_ALIGNOF(DummyNode)); } public: inline QHash() : d(const_cast(&QHashData::shared_null)) { } @@ -554,25 +558,14 @@ template Q_INLINE_TEMPLATE void QHash::duplicateNode(QHashData::Node *node, void *newNode) { Node *concreteNode = concrete(node); - if (QTypeInfo::isDummy) { - (void) new (newNode) DummyNode(concreteNode->key, concreteNode->h, 0); - } else { - (void) new (newNode) Node(concreteNode->key, concreteNode->value, concreteNode->h, 0); - } + new (newNode) Node(concreteNode->key, concreteNode->value, concreteNode->h, 0); } template Q_INLINE_TEMPLATE typename QHash::Node * QHash::createNode(uint ah, const Key &akey, const T &avalue, Node **anextNode) { - Node *node; - - if (QTypeInfo::isDummy) { - node = reinterpret_cast(new (d->allocateNode(alignOfDummyNode())) DummyNode(akey, ah, *anextNode)); - } else { - node = new (d->allocateNode(alignOfNode())) Node(akey, avalue, ah, *anextNode); - } - + Node *node = new (d->allocateNode(alignOfNode())) Node(akey, avalue, ah, *anextNode); *anextNode = node; ++d->size; return node; @@ -605,9 +598,7 @@ Q_INLINE_TEMPLATE void QHash::clear() template Q_OUTOFLINE_TEMPLATE void QHash::detach_helper() { - QHashData *x = d->detach_helper(duplicateNode, deleteNode2, - QTypeInfo::isDummy ? sizeof(DummyNode) : sizeof(Node), - QTypeInfo::isDummy ? alignOfDummyNode() : alignOfNode()); + QHashData *x = d->detach_helper(duplicateNode, deleteNode2, sizeof(Node), alignOfNode()); if (!d->ref.deref()) freeData(d); d = x; @@ -789,7 +780,7 @@ Q_INLINE_TEMPLATE typename QHash::iterator QHash::insert(const K return iterator(createNode(h, akey, avalue, node)); } - if (!QTypeInfo::isDummy) + if (!QtPrivate::is_same::value) (*node)->value = avalue; return iterator(*node); } @@ -958,7 +949,7 @@ Q_OUTOFLINE_TEMPLATE bool QHash::operator==(const QHash &other) do { if (it2 == other.end() || !(it2.key() == akey)) return false; - if (!QTypeInfo::isDummy && !(it.value() == it2.value())) + if (!(it.value() == it2.value())) return false; ++it; ++it2; -- cgit v1.2.3