diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2022-07-22 22:08:24 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2022-08-03 19:51:22 -0700 |
commit | 392e44539329017b04757e664400afaa7aacf7f5 (patch) | |
tree | 5325af8800eed84bfc89302785d449abf2b6005a /src/corelib/kernel/qvariant.cpp | |
parent | 0db329e48d071a89108d3dcc91df6f3fc4efe7b0 (diff) |
QVariant: don't leak PrivateShared if the constructor throws
This means we can't do a tail-call from customConstruct when
PrivateShared is in use. But the case without that is still a tail-call.
Change-Id: I3859764fed084846bcb0fffd17045d144181ea84
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib/kernel/qvariant.cpp')
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index be7be78d51..b7450cbafa 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -235,6 +235,21 @@ static bool isValidMetaTypeForVariant(const QtPrivate::QMetaTypeInterface *iface return true; } +template <typename F> static QVariant::PrivateShared * +customConstructShared(const QtPrivate::QMetaTypeInterface *iface, F &&construct) +{ + struct Deleter { + void operator()(QVariant::PrivateShared *p) const + { QVariant::PrivateShared::free(p); } + }; + + // this is exception-safe + std::unique_ptr<QVariant::PrivateShared, Deleter> ptr; + ptr.reset(QVariant::PrivateShared::create(iface)); + construct(ptr->data()); + return ptr.release(); +} + // the type of d has already been set, but other field are not set static void customConstruct(const QtPrivate::QMetaTypeInterface *iface, QVariant::Private *d, const void *copy) @@ -252,20 +267,17 @@ static void customConstruct(const QtPrivate::QMetaTypeInterface *iface, QVariant // ### Qt 7: remove nullptr_t special casing d->is_null = !copy QT6_ONLY(|| isInterfaceFor<std::nullptr_t>(iface)); - void *dst; if (QVariant::Private::canUseInternalSpace(iface)) { d->is_shared = false; - dst = &d->data; if (!copy && !iface->defaultCtr) return; // trivial default constructor, we've already memset + construct(iface, d->data.data, copy); } else { - d->data.shared = QVariant::PrivateShared::create(iface); + d->data.shared = customConstructShared(iface, [=](void *where) { + construct(iface, where, copy); + }); d->is_shared = true; - dst = d->data.shared->data(); } - - // now ask QMetaType to construct for us - construct(iface, dst, copy); } static void customClear(QVariant::Private *d) @@ -350,8 +362,9 @@ QVariant::Private::Private(std::piecewise_construct_t, const T &t) new (data.data) T(t); } else { static_assert(!isNothrowQVariantConstructible); // we allocate memory, even if T doesn't - data.shared = QVariant::PrivateShared::create(QtPrivate::qMetaTypeInterfaceForType<T>()); - new (data.shared->data()) T(t); + data.shared = customConstructShared(iface, [=](void *where) { + new (where) T(t); + }); } } |