summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qvariant.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2022-07-22 22:08:24 -0700
committerThiago Macieira <thiago.macieira@intel.com>2022-08-03 19:51:22 -0700
commit392e44539329017b04757e664400afaa7aacf7f5 (patch)
tree5325af8800eed84bfc89302785d449abf2b6005a /src/corelib/kernel/qvariant.cpp
parent0db329e48d071a89108d3dcc91df6f3fc4efe7b0 (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.cpp31
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);
+ });
}
}