From e1c719784a7fabf3d3e8cd6a250f8bfb3f4d2bad Mon Sep 17 00:00:00 2001 From: Fatih Uzunoglu <fuzun54@outlook.com> Date: Sat, 29 Mar 2025 21:09:26 +0200 Subject: [PATCH 1/2] qt: use `QPointer` for `QObject` members of `qt_intf_t` Although the pointers were set to null after the objects are destroyed, if for another reason the objects were destroyed (or never constructed and the pointers were not initialized), using a weak pointer can prevent unintentionally dereferencing dangling pointers. --- modules/gui/qt/qt.cpp | 19 +++---------------- modules/gui/qt/qt.hpp | 13 +++++++------ modules/gui/qt/util/model_recovery_agent.hpp | 2 +- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/modules/gui/qt/qt.cpp b/modules/gui/qt/qt.cpp index 57d25ed5dc14..aeabf0beb988 100644 --- a/modules/gui/qt/qt.cpp +++ b/modules/gui/qt/qt.cpp @@ -1087,7 +1087,6 @@ static void *Thread( void *obj ) { msg_Err(p_intf, "unable to create main interface"); delete p_intf->p_mi; - p_intf->p_mi = nullptr; //process deleteLater events as the main loop will never run QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); return ThreadCleanup( p_intf, CLEANUP_ERROR ); @@ -1180,32 +1179,20 @@ static void *ThreadCleanup( qt_intf_t *p_intf, CleanupReason cleanupReason ) MediaSourceCache::killInstance(); //destroy MainCtx, Compositor shouldn't not use MainCtx after `unloadGUI` - if (p_intf->p_mi) { - delete p_intf->p_mi; - p_intf->p_mi = nullptr; - } + delete p_intf->p_mi; if ( p_intf->p_compositor && cleanupReason == CLEANUP_APP_TERMINATED) { p_intf->p_compositor.reset(); delete p_intf->mainSettings; - p_intf->mainSettings = nullptr; } /* Destroy the main playlist controller */ - if (p_intf->p_mainPlaylistController) - { - delete p_intf->p_mainPlaylistController; - p_intf->p_mainPlaylistController = nullptr; - } + delete p_intf->p_mainPlaylistController; /* Destroy the main InputManager */ - if (p_intf->p_mainPlayerController) - { - delete p_intf->p_mainPlayerController; - p_intf->p_mainPlayerController = nullptr; - } + delete p_intf->p_mainPlayerController; /* Delete the application automatically */ return NULL; diff --git a/modules/gui/qt/qt.hpp b/modules/gui/qt/qt.hpp index b2a400e91e35..373522df7d45 100644 --- a/modules/gui/qt/qt.hpp +++ b/modules/gui/qt/qt.hpp @@ -37,6 +37,7 @@ #include <qconfig.h> #include <QString> +#include <QPointer> enum { IMEventTypeOffset = 0, @@ -83,15 +84,15 @@ struct qt_intf_t vlc_thread_t thread; - class MainCtx *p_mi; /* Main Interface, NULL if DialogProvider Mode */ - class QSettings *mainSettings; /* Qt State settings not messing main VLC ones */ + QPointer<class MainCtx> p_mi; /* Main Interface, NULL if DialogProvider Mode */ + QPointer<class QSettings> mainSettings; /* Qt State settings not messing main VLC ones */ bool b_isDialogProvider; /* Qt mode or Skins mode */ vlc_playlist_t *p_playlist; /* playlist */ vlc_player_t *p_player; /* player */ - vlc::playlist::PlaylistController* p_mainPlaylistController; - PlayerController* p_mainPlayerController; + QPointer<vlc::playlist::PlaylistController> p_mainPlaylistController; + QPointer<PlayerController> p_mainPlayerController; std::unique_ptr<vlc::Compositor> p_compositor; int refCount; @@ -116,8 +117,8 @@ public: }; #define THEDP DialogsProvider::getInstance() -#define THEMIM p_intf->p_mainPlayerController -#define THEMPL p_intf->p_mainPlaylistController +#define THEMIM p_intf->p_mainPlayerController.get() +#define THEMPL p_intf->p_mainPlaylistController.get() #define qfu( i ) QString::fromUtf8( i ) #define qfue( i ) QString::fromUtf8( i ).replace( "&", "&&" ) /* for actions/buttons */ diff --git a/modules/gui/qt/util/model_recovery_agent.hpp b/modules/gui/qt/util/model_recovery_agent.hpp index 3e2f36462e4d..5435bd50eb9d 100644 --- a/modules/gui/qt/util/model_recovery_agent.hpp +++ b/modules/gui/qt/util/model_recovery_agent.hpp @@ -45,7 +45,7 @@ class ModelRecoveryAgent public: // NOTE: settings and model must outlive the instance of this class. template<class T> - ModelRecoveryAgent(class QSettings *settings, const QString& modelIdentifier, T* model) + ModelRecoveryAgent(QPointer<QSettings> settings, const QString& modelIdentifier, QPointer<T> model) : m_settings(settings), m_key(modelIdentifier + QStringLiteral("/RecoveryFilePath")) { assert(settings); -- GitLab From 354d167ba0561ebace42751dae09963fb39da17c Mon Sep 17 00:00:00 2001 From: Fatih Uzunoglu <fuzun54@outlook.com> Date: Sat, 29 Mar 2025 21:17:30 +0200 Subject: [PATCH 2/2] qt: do not construct `ModelRecoveryAgent` if settings or playlist controller do not exist `ModelRecoveryAgent` requires valid settings and playlist controller instances. It can not be constructed when they do not exist. This is an extremely unlikely case (but not impossible), because given the structure of the application it is expected that they are valid when `ModelRecoveryAgent` is constructed. It should be noted that the reason `ModelRecoveryAgent` construction is delayed through queued connection is only to not prolong the application startup time. --- modules/gui/qt/qt.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/gui/qt/qt.cpp b/modules/gui/qt/qt.cpp index aeabf0beb988..3265a2637c51 100644 --- a/modules/gui/qt/qt.cpp +++ b/modules/gui/qt/qt.cpp @@ -1027,11 +1027,12 @@ static void *Thread( void *obj ) p_intf->p_mainPlaylistController = new vlc::playlist::PlaylistController(p_intf->p_playlist); std::unique_ptr<ModelRecoveryAgent> playlistModelRecoveryAgent; - QMetaObject::invokeMethod(&app, [&playlistModelRecoveryAgent, p_intf]() { + QMetaObject::invokeMethod(&app, [&playlistModelRecoveryAgent, settings = p_intf->mainSettings, playlistController = p_intf->p_mainPlaylistController]() { try { - playlistModelRecoveryAgent = std::make_unique<ModelRecoveryAgent>(p_intf->mainSettings, - QStringLiteral("Playlist"), - p_intf->p_mainPlaylistController); + if (Q_LIKELY(settings && playlistController)) + playlistModelRecoveryAgent = std::make_unique<ModelRecoveryAgent>(settings, + QStringLiteral("Playlist"), + playlistController); } catch (...){ } }, Qt::QueuedConnection); -- GitLab