diff options
author | Marc Mutz <marc.mutz@kdab.com> | 2021-08-02 15:01:40 +0200 |
---|---|---|
committer | Marc Mutz <marc.mutz@kdab.com> | 2021-08-04 13:32:40 +0200 |
commit | fa7f4c5efd91c852341dd2e56396ee3f5fedd33a (patch) | |
tree | f0dfe0af5b2d0e5dc1b643e648511916147dcded /src/corelib/kernel/qmetatype.h | |
parent | e933d71a610a951cc6af3c2ac40b97037a14bf9c (diff) |
QMetaType: auto-unregister converters and mutable views again
The port from hand-rolled function storage to std::function
inadvertently removed the helper variable of static storage duration
whose dtor would unregister the conversion function. This caused
QTBUG-94831, where the cleanup of conversion functions attempts to
call code (via std::function) from a library that has already been
unloaded.
Restore the 5.15 behavior by adding a static-storage-duration scope
guard to unregister the conversion and view functions from Qt upon
library unload (when static objects are destroyed). Unlike 5.15, only
install the scope guard upon successful registration, ensuring that
only the DLL which successfully registered its conversion function
unregisters it again.
Amends 0e4ae4fbf8e320d18c29a55b5db2bba25b3d9d50.
Add some strategic std::move()s as a drive-by.
Pick-to: 6.2
Task-number: QTBUG-94831
Change-Id: I391ca667420cf0d98a166676b9bb363d6e190306
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel/qmetatype.h')
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 45 |
1 files changed, 37 insertions, 8 deletions
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index adc4ae92d5..6611e34c33 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -48,6 +48,7 @@ #include <QtCore/qcompare.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qrefcount.h> +#include <QtCore/qscopeguard.h> #include <QtCore/qdatastream.h> #include <QtCore/qiterable.h> #ifndef QT_NO_QOBJECT @@ -570,7 +571,7 @@ public: *t = (f->*function)(); return true; }; - return registerConverterFunction(converter, fromType, toType); + return registerConverterImpl<From, To>(converter, fromType, toType); } // member function @@ -588,7 +589,7 @@ public: *t = (f->*function)(); return true; }; - return registerMutableViewFunction(view, fromType, toType); + return registerMutableViewImpl<From, To>(view, fromType, toType); } // member function as in "double QString::toDouble(bool *ok = nullptr) const" @@ -609,7 +610,7 @@ public: *t = To(); return result; }; - return registerConverterFunction(converter, fromType, toType); + return registerConverterImpl<From, To>(converter, fromType, toType); } // functor or function pointer @@ -621,13 +622,13 @@ public: const QMetaType fromType = QMetaType::fromType<From>(); const QMetaType toType = QMetaType::fromType<To>(); - auto converter = [function](const void *from, void *to) -> bool { + auto converter = [function = std::move(function)](const void *from, void *to) -> bool { const From *f = static_cast<const From *>(from); To *t = static_cast<To *>(to); *t = function(*f); return true; }; - return registerConverterFunction(converter, fromType, toType); + return registerConverterImpl<From, To>(std::move(converter), fromType, toType); } // functor or function pointer @@ -639,15 +640,43 @@ public: const QMetaType fromType = QMetaType::fromType<From>(); const QMetaType toType = QMetaType::fromType<To>(); - auto view = [function](void *from, void *to) -> bool { + auto view = [function = std::move(function)](void *from, void *to) -> bool { From *f = static_cast<From *>(from); To *t = static_cast<To *>(to); *t = function(*f); return true; }; - return registerMutableViewFunction(view, fromType, toType); + return registerMutableViewImpl<From, To>(std::move(view), fromType, toType); } -#endif + +private: + template<typename From, typename To> + static bool registerConverterImpl(ConverterFunction converter, QMetaType fromType, QMetaType toType) + { + if (registerConverterFunction(std::move(converter), fromType, toType)) { + static const auto unregister = qScopeGuard([=] { + unregisterConverterFunction(fromType, toType); + }); + return true; + } else { + return false; + } + } + + template<typename From, typename To> + static bool registerMutableViewImpl(MutableViewFunction view, QMetaType fromType, QMetaType toType) + { + if (registerMutableViewFunction(std::move(view), fromType, toType)) { + static const auto unregister = qScopeGuard([=] { + unregisterMutableViewFunction(fromType, toType); + }); + return true; + } else { + return false; + } + } +#endif // Q_CLANG_DOC +public: static bool convert(QMetaType fromType, const void *from, QMetaType toType, void *to); static bool canConvert(QMetaType fromType, QMetaType toType); |