Make QExplicitlySharedDataPointer<T> copy-ctor from QESDP<X> more safe
With "QExplicitlySharedDataPointer::QExplicitlySharedDataPointer( const QExplicitlySharedDataPointer<X> & other)" implicitly doing an static_cast<T *>(...) on other.data(), this could lead to dangerous use of this copy constructor. Example code: QExplicitlySharedDataPointer<Base> base(new Base); QExplicitlySharedDataPointer<Derived> derived(base); // that works! This patchs disables the use of the static_cast, and adds a new define called QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST to re-enable that code path. Note, that the other way-around (assigning 'derived' to 'base') still works as intended. Other side note: QtXmlPatterns is relying heavily on the hidden static_cast "feature". The other default Qt modules compile fine with the static_cast removed. [ChangeLog][Important Behavior Changes] QExplicitelySharedDataPointer's copy constructor which performs a static_cast from "X *" to "T *" (when constructing a QExplicitlySharedDataPointer<T> from a QExplicitlySharedDataPointer<X>) doesn't perform a static_cast from "X *" to "T *" any more. Instead, an implicit cast is now performed. This change will break compilation of code that relied on the downcast (i.e. cast towards a more derived type) of the templated type when copy costructing a QExplicitelySharedDataPointer object. Please refer to the class documentation for more information about this issue and a workaround to keep old code compiling. Change-Id: Id32aba6cda4e6d44728d7bc3a5c0c7a20f19adc6 Reviewed-by: Kevin Funk <kevin.funk@kdab.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
01cc625406
commit
e112c2ee20
@ -538,10 +538,34 @@ QT_BEGIN_NAMESPACE
|
||||
/*! \fn QExplicitlySharedDataPointer::QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X>& other)
|
||||
This copy constructor is different in that it allows \a other to be
|
||||
a different type of explicitly shared data pointer but one that has
|
||||
a compatible shared data object. It performs a static cast of the
|
||||
\e{d pointer} in \a other and sets the \e {d pointer} of \e this to
|
||||
the converted \e{d pointer}. It increments the reference count of
|
||||
the shared data object.
|
||||
a compatible shared data object.
|
||||
|
||||
By default, the \e{d pointer} of \a other (of type \c{X *}) gets
|
||||
implicitly converted to the type \c{T *}; the result of this
|
||||
conversion is set as the \e{d pointer} of \e{this}, and the
|
||||
reference count of the shared data object is incremented.
|
||||
|
||||
However, if the macro
|
||||
\c{QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST} is defined
|
||||
before including the \c{QExplicitlySharedDataPointer} header, then
|
||||
the \e{d pointer} of \a other undergoes a \c{static_cast} to the
|
||||
type \c{T *}. The result of the cast is then set as the
|
||||
\e{d pointer} of \e{this}, and the reference count of the shared data
|
||||
object is incremented.
|
||||
|
||||
\warning relying on such \c{static_cast} is potentially dangerous,
|
||||
because it allows code like this to compile:
|
||||
|
||||
\code
|
||||
QExplicitlySharedDataPointer<Base> base(new Base);
|
||||
QExplicitlySharedDataPointer<Derived> derived(base); // !!! DANGER !!!
|
||||
\endcode
|
||||
|
||||
Starting from Qt 5.4 the cast is disabled by default. It is
|
||||
possible to enable it back by defining the
|
||||
\c{QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST} macro, and
|
||||
therefore to allow old code (that relied on this feature) to
|
||||
compile without modifications.
|
||||
*/
|
||||
|
||||
/*! \fn QExplicitlySharedDataPointer<T>& QExplicitlySharedDataPointer::operator=(const QExplicitlySharedDataPointer<T>& other)
|
||||
|
@ -167,7 +167,12 @@ public:
|
||||
inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<T> &o) : d(o.d) { if (d) d->ref.ref(); }
|
||||
|
||||
template<class X>
|
||||
inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o) : d(static_cast<T *>(o.data()))
|
||||
inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o)
|
||||
#ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST
|
||||
: d(static_cast<T *>(o.data()))
|
||||
#else
|
||||
: d(o.data())
|
||||
#endif
|
||||
{
|
||||
if(d)
|
||||
d->ref.ref();
|
||||
|
Loading…
Reference in New Issue
Block a user