From fa7f4c5efd91c852341dd2e56396ee3f5fedd33a Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 2 Aug 2021 15:01:40 +0200 Subject: [PATCH] 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 --- src/corelib/kernel/qmetatype.h | 45 ++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index adc4ae92d5a..6611e34c334 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #ifndef QT_NO_QOBJECT @@ -570,7 +571,7 @@ public: *t = (f->*function)(); return true; }; - return registerConverterFunction(converter, fromType, toType); + return registerConverterImpl(converter, fromType, toType); } // member function @@ -588,7 +589,7 @@ public: *t = (f->*function)(); return true; }; - return registerMutableViewFunction(view, fromType, toType); + return registerMutableViewImpl(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(converter, fromType, toType); } // functor or function pointer @@ -621,13 +622,13 @@ public: const QMetaType fromType = QMetaType::fromType(); const QMetaType toType = QMetaType::fromType(); - 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(from); To *t = static_cast(to); *t = function(*f); return true; }; - return registerConverterFunction(converter, fromType, toType); + return registerConverterImpl(std::move(converter), fromType, toType); } // functor or function pointer @@ -639,15 +640,43 @@ public: const QMetaType fromType = QMetaType::fromType(); const QMetaType toType = QMetaType::fromType(); - auto view = [function](void *from, void *to) -> bool { + auto view = [function = std::move(function)](void *from, void *to) -> bool { From *f = static_cast(from); To *t = static_cast(to); *t = function(*f); return true; }; - return registerMutableViewFunction(view, fromType, toType); + return registerMutableViewImpl(std::move(view), fromType, toType); } -#endif + +private: + template + 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 + 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);