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 <thiago.macieira@intel.com>
This commit is contained in:
Olivier Goffart 2014-07-03 13:38:59 +02:00
parent 84e189502a
commit 813af5f065
2 changed files with 17 additions and 26 deletions

View File

@ -64,7 +64,7 @@ public:
isComplex = true,
isStatic = true,
isLarge = (sizeof(T)>sizeof(void*)),
isDummy = false,
isDummy = false, //### Qt6: remove
sizeOf = sizeof(T)
};
};

View File

@ -217,17 +217,23 @@ private:
Q_DISABLE_COPY(QHashNode)
};
template <class Key, class T>
struct QHashDummyNode
// Specialize for QHashDummyValue in order to save some memory
template <class Key>
struct QHashNode<Key, QHashDummyValue>
{
QHashNode<Key, T> *next;
union {
QHashNode *next;
QHashDummyValue value;
};
const uint h;
const Key key;
inline QHashDummyNode(const Key &key0, uint hash, QHashNode<Key, T> *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 Key, class T>
class QHash
{
typedef QHashDummyNode<Key, T> DummyNode;
typedef QHashNode<Key, T> Node;
union {
@ -289,7 +294,6 @@ class QHash
}
static inline int alignOfNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(Node)); }
static inline int alignOfDummyNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(DummyNode)); }
public:
inline QHash() : d(const_cast<QHashData *>(&QHashData::shared_null)) { }
@ -554,25 +558,14 @@ template <class Key, class T>
Q_INLINE_TEMPLATE void QHash<Key, T>::duplicateNode(QHashData::Node *node, void *newNode)
{
Node *concreteNode = concrete(node);
if (QTypeInfo<T>::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 <class Key, class T>
Q_INLINE_TEMPLATE typename QHash<Key, T>::Node *
QHash<Key, T>::createNode(uint ah, const Key &akey, const T &avalue, Node **anextNode)
{
Node *node;
if (QTypeInfo<T>::isDummy) {
node = reinterpret_cast<Node *>(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<Key, T>::clear()
template <class Key, class T>
Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::detach_helper()
{
QHashData *x = d->detach_helper(duplicateNode, deleteNode2,
QTypeInfo<T>::isDummy ? sizeof(DummyNode) : sizeof(Node),
QTypeInfo<T>::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<Key, T>::iterator QHash<Key, T>::insert(const K
return iterator(createNode(h, akey, avalue, node));
}
if (!QTypeInfo<T>::isDummy)
if (!QtPrivate::is_same<T, QHashDummyValue>::value)
(*node)->value = avalue;
return iterator(*node);
}
@ -958,7 +949,7 @@ Q_OUTOFLINE_TEMPLATE bool QHash<Key, T>::operator==(const QHash<Key, T> &other)
do {
if (it2 == other.end() || !(it2.key() == akey))
return false;
if (!QTypeInfo<T>::isDummy && !(it.value() == it2.value()))
if (!(it.value() == it2.value()))
return false;
++it;
++it2;