summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@nokia.com>2009-05-14 16:30:57 (GMT)
committerThiago Macieira <thiago.macieira@nokia.com>2009-05-18 14:24:02 (GMT)
commitd76c5fb7feda66621b435263353f49e9b4b34308 (patch)
treeda4b27c60127d4386abad70c7abc6c7d61539c04
parentd13162dd4695274dc4bdb286ce85bf198391d94b (diff)
downloadQt-d76c5fb7feda66621b435263353f49e9b4b34308.zip
Qt-d76c5fb7feda66621b435263353f49e9b4b34308.tar.gz
Qt-d76c5fb7feda66621b435263353f49e9b4b34308.tar.bz2
Fix handling of dynamic casts in QSharedPointer.
It's wrong to assume that static_cast<> is allowed everywhere where dynamic_cast<> is allowed. For example, if class C derives from both A and B, then you can dynamic_cast<B *>(ptr_to_A), but you can't static_cast. So introduce a helper for dynamic casts that doesn't do static_cast. Reviewed-by: Olivier Goffart
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h21
-rw-r--r--tests/auto/qsharedpointer/tst_qsharedpointer.cpp137
2 files changed, 140 insertions, 18 deletions
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h
index f1b35ee..ad2d9f2 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -238,6 +238,7 @@ namespace QtSharedPointer {
template <class X> friend class ExternalRefCount;
template <class X> friend class QWeakPointer;
template <class X, class Y> friend QSharedPointer<X> qSharedPointerCastHelper(const QSharedPointer<Y> &src, X *);
+ template <class X, class Y> friend QSharedPointer<X> qSharedPointerDynamicCastHelper(const QSharedPointer<Y> &src, X *);
template <class X, class Y> friend QSharedPointer<X> qSharedPointerConstCastHelper(const QSharedPointer<Y> &src, X *);
template <class X, class Y> friend QSharedPointer<X> QtSharedPointer::qStrongRefFromWeakHelper(const QWeakPointer<Y> &src, X *);
#endif
@@ -509,6 +510,14 @@ namespace QtSharedPointer {
return result;
}
template <class X, class T>
+ Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCastHelper(const QSharedPointer<T> &src, X *)
+ {
+ QSharedPointer<X> result;
+ register T *ptr = src.data();
+ result.internalSet(src.d, dynamic_cast<X *>(ptr));
+ return result;
+ }
+ template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCastHelper(const QSharedPointer<T> &src, X *)
{
QSharedPointer<X> result;
@@ -544,9 +553,7 @@ template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCast(const QSharedPointer<T> &src)
{
X *x = 0;
- if (QtSharedPointer::qVerifyDynamicCast(src.data(), x))
- return QtSharedPointer::qSharedPointerCastHelper(src, x);
- return QSharedPointer<X>();
+ return QtSharedPointer::qSharedPointerDynamicCastHelper(src, x);
}
template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerDynamicCast(const QWeakPointer<T> &src)
@@ -558,17 +565,13 @@ template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &src)
{
X *x = 0;
- if (QtSharedPointer::qVerifyConstCast(src.data(), x))
- return QtSharedPointer::qSharedPointerConstCastHelper(src, x);
- return QSharedPointer<X>();
+ return QtSharedPointer::qSharedPointerConstCastHelper(src, x);
}
template <class X, class T>
Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerConstCast(const QWeakPointer<T> &src)
{
X *x = 0;
- if (QtSharedPointer::qVerifyConstCast(src.data(), x))
- return QtSharedPointer::qSharedPointerCastHelper(src, x);
- return QSharedPointer<X>();
+ return QtSharedPointer::qSharedPointerConstCastHelper(src, x);
}
template <class X, class T>
diff --git a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp
index 64439fb..a52bb3e 100644
--- a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp
+++ b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp
@@ -57,8 +57,11 @@ private slots:
void downCast();
void upCast();
void differentPointers();
+ void virtualBaseDifferentPointers();
#ifndef QTEST_NO_RTTI
void dynamicCast();
+ void dynamicCastDifferentPointers();
+ void dynamicCastVirtualBase();
void dynamicCastFailure();
#endif
void customDeleter();
@@ -321,6 +324,10 @@ class DiffPtrDerivedData: public Stuffing, public Data
{
};
+class VirtualDerived: virtual public Data
+{
+};
+
void tst_QSharedPointer::downCast()
{
{
@@ -439,7 +446,7 @@ void tst_QSharedPointer::differentPointers()
DiffPtrDerivedData *aData = new DiffPtrDerivedData;
Data *aBase = aData;
Q_ASSERT(aData == aBase);
- Q_ASSERT(quintptr(&aData) != quintptr(&aBase));
+ Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData);
QSharedPointer<DiffPtrDerivedData> ptr = qSharedPointerCast<DiffPtrDerivedData>(baseptr);
@@ -453,7 +460,7 @@ void tst_QSharedPointer::differentPointers()
DiffPtrDerivedData *aData = new DiffPtrDerivedData;
Data *aBase = aData;
Q_ASSERT(aData == aBase);
- Q_ASSERT(quintptr(&aData) != quintptr(&aBase));
+ Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
QSharedPointer<DiffPtrDerivedData> ptr = QSharedPointer<DiffPtrDerivedData>(aData);
QSharedPointer<Data> baseptr = ptr;
@@ -464,23 +471,53 @@ void tst_QSharedPointer::differentPointers()
QVERIFY(baseptr == aData);
QVERIFY(baseptr == aBase);
}
+}
+
+void tst_QSharedPointer::virtualBaseDifferentPointers()
+{
+ {
+ VirtualDerived *aData = new VirtualDerived;
+ Data *aBase = aData;
+ Q_ASSERT(aData == aBase);
+ Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
+
+ QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>(aData);
+ QSharedPointer<Data> baseptr = qSharedPointerCast<Data>(ptr);
+ QVERIFY(ptr == baseptr);
+ QVERIFY(ptr.data() == baseptr.data());
+ QVERIFY(ptr == aBase);
+ QVERIFY(ptr == aData);
+ QVERIFY(baseptr == aData);
+ QVERIFY(baseptr == aBase);
+ }
+
+ {
+ VirtualDerived *aData = new VirtualDerived;
+ Data *aBase = aData;
+ Q_ASSERT(aData == aBase);
+ Q_ASSERT(*reinterpret_cast<quintptr *>(&aData) != *reinterpret_cast<quintptr *>(&aBase));
- // there is no possibility for different pointers in
- // internal reference counting right now
- //
- // to do that, it's necessary to first implement the ability to
- // call (virtual) functions, so that the two differing bases have
- // the same reference counter
+ QSharedPointer<VirtualDerived> ptr = QSharedPointer<VirtualDerived>(aData);
+ QSharedPointer<Data> baseptr = ptr;
+ QVERIFY(ptr == baseptr);
+ QVERIFY(ptr.data() == baseptr.data());
+ QVERIFY(ptr == aBase);
+ QVERIFY(ptr == aData);
+ QVERIFY(baseptr == aData);
+ QVERIFY(baseptr == aBase);
+ }
}
#ifndef QTEST_NO_RTTI
void tst_QSharedPointer::dynamicCast()
{
- QSharedPointer<Data> baseptr = QSharedPointer<Data>(new DerivedData);
+ DerivedData *aData = new DerivedData;
+ QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData);
{
QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(baseptr);
QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
}
QCOMPARE(int(baseptr.d->weakref), 1);
@@ -490,6 +527,7 @@ void tst_QSharedPointer::dynamicCast()
QWeakPointer<Data> weakptr = baseptr;
QSharedPointer<DerivedData> derivedptr = qSharedPointerDynamicCast<DerivedData>(weakptr);
QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
}
QCOMPARE(int(baseptr.d->weakref), 1);
@@ -498,6 +536,87 @@ void tst_QSharedPointer::dynamicCast()
{
QSharedPointer<DerivedData> derivedptr = baseptr.dynamicCast<DerivedData>();
QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(baseptr.d->weakref), 1);
+ QCOMPARE(int(baseptr.d->strongref), 1);
+}
+
+void tst_QSharedPointer::dynamicCastDifferentPointers()
+{
+ // DiffPtrDerivedData derives from both Data and Stuffing
+ DiffPtrDerivedData *aData = new DiffPtrDerivedData;
+ QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData);
+
+ {
+ QSharedPointer<DiffPtrDerivedData> derivedptr = qSharedPointerDynamicCast<DiffPtrDerivedData>(baseptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(baseptr.d->weakref), 1);
+ QCOMPARE(int(baseptr.d->strongref), 1);
+
+ {
+ QWeakPointer<Data> weakptr = baseptr;
+ QSharedPointer<DiffPtrDerivedData> derivedptr = qSharedPointerDynamicCast<DiffPtrDerivedData>(weakptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(baseptr.d->weakref), 1);
+ QCOMPARE(int(baseptr.d->strongref), 1);
+
+ {
+ QSharedPointer<DiffPtrDerivedData> derivedptr = baseptr.dynamicCast<DiffPtrDerivedData>();
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(baseptr.d->weakref), 1);
+ QCOMPARE(int(baseptr.d->strongref), 1);
+
+ {
+ Stuffing *nakedptr = dynamic_cast<Stuffing *>(baseptr.data());
+ QVERIFY(nakedptr);
+
+ QSharedPointer<Stuffing> otherbaseptr = qSharedPointerDynamicCast<Stuffing>(baseptr);
+ QVERIFY(!otherbaseptr.isNull());
+ QVERIFY(otherbaseptr == nakedptr);
+ QCOMPARE(otherbaseptr.data(), nakedptr);
+ QCOMPARE(static_cast<DiffPtrDerivedData*>(otherbaseptr.data()), aData);
+ }
+}
+
+void tst_QSharedPointer::dynamicCastVirtualBase()
+{
+ VirtualDerived *aData = new VirtualDerived;
+ QSharedPointer<Data> baseptr = QSharedPointer<Data>(aData);
+
+ {
+ QSharedPointer<VirtualDerived> derivedptr = qSharedPointerDynamicCast<VirtualDerived>(baseptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(baseptr.d->weakref), 1);
+ QCOMPARE(int(baseptr.d->strongref), 1);
+
+ {
+ QWeakPointer<Data> weakptr = baseptr;
+ QSharedPointer<VirtualDerived> derivedptr = qSharedPointerDynamicCast<VirtualDerived>(weakptr);
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
+ QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
+ }
+ QCOMPARE(int(baseptr.d->weakref), 1);
+ QCOMPARE(int(baseptr.d->strongref), 1);
+
+ {
+ QSharedPointer<VirtualDerived> derivedptr = baseptr.dynamicCast<VirtualDerived>();
+ QVERIFY(baseptr == derivedptr);
+ QCOMPARE(derivedptr.data(), aData);
QCOMPARE(static_cast<Data *>(derivedptr.data()), baseptr.data());
}
QCOMPARE(int(baseptr.d->weakref), 1);