From 5315496361314009468553577251329079179996 Mon Sep 17 00:00:00 2001 From: Glenn Smith Date: Tue, 13 Feb 2024 16:23:58 -0500 Subject: Type Browser: Fix crash on close with more shared pointers --- ui/typebrowser.h | 83 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 23 deletions(-) diff --git a/ui/typebrowser.h b/ui/typebrowser.h index df0104dc..c1d554ad 100644 --- a/ui/typebrowser.h +++ b/ui/typebrowser.h @@ -43,13 +43,13 @@ public: typedef std::function UpdateNodeCallback; protected: - class TypeBrowserModel* m_model; + class TypeBrowserModelData* m_model; std::optional> m_parent; std::vector> m_children; std::map m_childIndices; bool m_hasGeneratedChildren; - TypeBrowserTreeNode(class TypeBrowserModel* model, std::optional> parent); + TypeBrowserTreeNode(class TypeBrowserModelData* model, std::optional> parent); virtual ~TypeBrowserTreeNode() = default; virtual void generateChildren() = 0; void updateChildIndices(); @@ -58,7 +58,7 @@ protected: void addChild(std::shared_ptr child); public: - class TypeBrowserModel* model() const { return m_model; } + class TypeBrowserModelData* model() const { return m_model; } std::optional> parent() const; const std::vector>& children(); int indexOfChild(std::shared_ptr child) const; @@ -73,7 +73,7 @@ public: class BINARYNINJAUIAPI EmptyTreeNode : public TypeBrowserTreeNode { public: - EmptyTreeNode(class TypeBrowserModel* model, std::optional> parent); + EmptyTreeNode(class TypeBrowserModelData* model, std::optional> parent); virtual ~EmptyTreeNode() = default; virtual std::string text(int column) const override; @@ -91,7 +91,7 @@ class BINARYNINJAUIAPI RootTreeNode : public TypeBrowserTreeNode std::map> m_containerNodes; public: - RootTreeNode(class TypeBrowserModel* model, std::optional> parent); + RootTreeNode(class TypeBrowserModelData* model, std::optional> parent); virtual ~RootTreeNode() = default; virtual std::string text(int column) const override; @@ -132,7 +132,7 @@ private: std::optional m_sourceOriginalName; public: - TypeTreeNode(class TypeBrowserModel* model, std::optional> parent, const std::string& id, BinaryNinja::QualifiedName name, TypeRef type); + TypeTreeNode(class TypeBrowserModelData* model, std::optional> parent, const std::string& id, BinaryNinja::QualifiedName name, TypeRef type); virtual ~TypeTreeNode() = default; const std::string& id() const { return m_id; } @@ -161,7 +161,7 @@ class BINARYNINJAUIAPI TypeContainerTreeNode : public TypeBrowserTreeNode std::map, std::shared_ptr>> m_typeNodes; public: - TypeContainerTreeNode(class TypeBrowserModel* model, std::optional> parent, const std::string& m_containerId); + TypeContainerTreeNode(class TypeBrowserModelData* model, std::optional> parent, const std::string& m_containerId); virtual ~TypeContainerTreeNode(); virtual std::string text(int column) const override; @@ -180,18 +180,19 @@ protected: //----------------------------------------------------------------------------- - -class BINARYNINJAUIAPI TypeBrowserModel : public QAbstractItemModel, public BinaryNinja::BinaryDataNotification, public BinaryNinja::TypeArchiveNotification +/*! Cursed data struct behind a shared_ptr so Qt stops deleting our model while the background updates run */ +class TypeBrowserModelData: public std::enable_shared_from_this { - Q_OBJECT BinaryViewRef m_data; + + mutable std::recursive_mutex m_rootNodeMutex; // Controls m_rootNode std::shared_ptr m_rootNode; - mutable std::recursive_mutex m_rootNodeMutex; + + std::recursive_mutex m_stateMutex; // Controls m_needsUpdate, m_updating bool m_needsUpdate; bool m_updating; - std::recursive_mutex m_updateMutex; - std::vector> m_updateCallbacks; + std::mutex m_backgroundTaskMutex; std::vector m_containerIds; std::map m_containerNames; @@ -206,15 +207,19 @@ class BINARYNINJAUIAPI TypeBrowserModel : public QAbstractItemModel, public Bina std::map m_containerPlatforms; void addContainer(BinaryNinja::TypeContainer cont); - void callUpdateCallbacks(); - void commitUpdate(TypeBrowserTreeNode::UpdateData& update); - void commitUpdates(std::vector& updates); + + friend class TypeBrowserModel; public: - TypeBrowserModel(BinaryViewRef data, QObject* parent); - virtual ~TypeBrowserModel(); - BinaryViewRef getData() { return m_data; } - std::shared_ptr getRootNode() { return m_rootNode; } + explicit TypeBrowserModelData(BinaryViewRef data); + ~TypeBrowserModelData(); + TypeBrowserModelData(const TypeBrowserModelData&) = delete; + TypeBrowserModelData(TypeBrowserModelData&&) = delete; + TypeBrowserModelData& operator=(const TypeBrowserModelData&) = delete; + TypeBrowserModelData& operator=(TypeBrowserModelData&&) = delete; + + BinaryViewRef getData(); + std::shared_ptr getRootNode(); std::vector containerIds() const; @@ -240,6 +245,40 @@ public: void addContainerForPlatform(PlatformRef platform); void clearContainers(); + std::vector> containerNodes() const; +}; + +//----------------------------------------------------------------------------- + +class BINARYNINJAUIAPI TypeBrowserModel : public QAbstractItemModel, public BinaryNinja::BinaryDataNotification, public BinaryNinja::TypeArchiveNotification +{ + Q_OBJECT + + BinaryViewRef m_data; + std::shared_ptr m_modelData; + + void commitUpdate(const TypeBrowserTreeNode::UpdateData& update); + void commitUpdates(const std::vector& updates); + +public: + TypeBrowserModel(BinaryViewRef data, QObject* parent); + virtual ~TypeBrowserModel(); + BinaryViewRef getData(); + std::shared_ptr getRootNode(); + + std::vector containerIds() const; + std::vector> containerNodes() const; + + std::string nameForContainerId(const std::string& id) const; + std::optional> containerForContainerId(const std::string& id); + std::optional> containerForContainerId(const std::string& id) const; + std::optional viewForContainerId(const std::string& id) const; + std::optional archiveForContainerId(const std::string& id) const; + std::optional archiveIdForContainerId(const std::string& id) const; + std::optional libraryForContainerId(const std::string& id) const; + std::optional debugInfoForContainerId(const std::string& id) const; + std::optional platformForContainerId(const std::string& id) const; + void updateFonts(); void runAfterUpdate(std::function callback); @@ -253,8 +292,6 @@ public: std::shared_ptr nodeForIndex(const QModelIndex& index) const; QModelIndex indexForNode(std::shared_ptr node, int column = 0) const; - std::vector> containerNodes() const; - bool filter(const QModelIndex& index, const std::string& filter, TypeBrowserFilterMode mode) const; bool lessThan(const QModelIndex& left, const QModelIndex& right) const; @@ -275,7 +312,7 @@ public: Q_SIGNALS: void updatesAboutToHappen(); - void updateComplete(); + void updateComplete(bool didAnyHappen); public Q_SLOTS: void markDirty(); -- cgit v1.3.1