Fix Use After Free MessageDelegateBase

Make sure that a `MessageDelegateBase` is not used after free by a `MessageObjectIncubator` callback by tracking them and cleaning them up on deletion of a `MessageDelegateBase`
This commit is contained in:
James Graham
2025-06-17 17:19:38 +01:00
parent 1860de12ea
commit 3183e00acc
2 changed files with 20 additions and 0 deletions

View File

@@ -49,6 +49,14 @@ MessageDelegateBase::MessageDelegateBase(QQuickItem *parent)
connect(&m_contentSizeHelper, &DelegateSizeHelper::availableWidthChanged, this, &MessageDelegateBase::markAsDirty); connect(&m_contentSizeHelper, &DelegateSizeHelper::availableWidthChanged, this, &MessageDelegateBase::markAsDirty);
} }
MessageDelegateBase::~MessageDelegateBase()
{
for (const auto &incubator : m_activeIncubators) {
incubator->clear();
delete incubator;
}
}
NeochatRoomMember *MessageDelegateBase::author() const NeochatRoomMember *MessageDelegateBase::author() const
{ {
return m_author; return m_author;
@@ -139,6 +147,10 @@ qreal MessageDelegateBase::maxContentWidth() const
void MessageDelegateBase::cleanupIncubator(MessageObjectIncubator *incubator) void MessageDelegateBase::cleanupIncubator(MessageObjectIncubator *incubator)
{ {
incubator->clear(); incubator->clear();
const auto it = std::find(m_activeIncubators.begin(), m_activeIncubators.end(), incubator);
if (it != m_activeIncubators.end()) {
m_activeIncubators.erase(it);
}
delete incubator; delete incubator;
} }
@@ -233,6 +245,7 @@ void MessageDelegateBase::updateAvatar()
cleanupIncubator(incubator); cleanupIncubator(incubator);
}, },
m_errorCallback); m_errorCallback);
m_activeIncubators.push_back(avatarIncubator);
m_avatarComponent->create(*avatarIncubator, qmlContext(m_avatarComponent)); m_avatarComponent->create(*avatarIncubator, qmlContext(m_avatarComponent));
m_avatarIncubating = true; m_avatarIncubating = true;
} else if (!showAvatar() && m_avatarItem) { } else if (!showAvatar() && m_avatarItem) {
@@ -296,6 +309,7 @@ void MessageDelegateBase::updateSection()
cleanupIncubator(incubator); cleanupIncubator(incubator);
}, },
m_errorCallback); m_errorCallback);
m_activeIncubators.push_back(sectionIncubator);
m_sectionComponent->create(*sectionIncubator, qmlContext(m_sectionComponent)); m_sectionComponent->create(*sectionIncubator, qmlContext(m_sectionComponent));
m_sectionIncubating = true; m_sectionIncubating = true;
} else if (!m_showSection && m_sectionItem) { } else if (!m_showSection && m_sectionItem) {
@@ -359,6 +373,7 @@ void MessageDelegateBase::updateReadMarker()
cleanupIncubator(incubator); cleanupIncubator(incubator);
}, },
m_errorCallback); m_errorCallback);
m_activeIncubators.push_back(readMarkerIncubator);
m_readMarkerComponent->create(*readMarkerIncubator, qmlContext(m_readMarkerComponent)); m_readMarkerComponent->create(*readMarkerIncubator, qmlContext(m_readMarkerComponent));
m_readMarkerIncubating = true; m_readMarkerIncubating = true;
} else if (!m_showReadMarkers && m_readMarkerItem) { } else if (!m_showReadMarkers && m_readMarkerItem) {
@@ -428,6 +443,7 @@ void MessageDelegateBase::updateBackground()
cleanupIncubator(incubator); cleanupIncubator(incubator);
}, },
m_errorCallback); m_errorCallback);
m_activeIncubators.push_back(compactBackgroundIncubator);
m_compactBackgroundComponent->create(*compactBackgroundIncubator, qmlContext(m_compactBackgroundComponent)); m_compactBackgroundComponent->create(*compactBackgroundIncubator, qmlContext(m_compactBackgroundComponent));
m_compactBackgroundIncubating = true; m_compactBackgroundIncubating = true;
} else if (m_compactBackgroundItem && !m_hovered) { } else if (m_compactBackgroundItem && !m_hovered) {
@@ -476,6 +492,7 @@ void MessageDelegateBase::updateQuickAction()
cleanupIncubator(incubator); cleanupIncubator(incubator);
}, },
m_errorCallback); m_errorCallback);
m_activeIncubators.push_back(quickActionIncubator);
m_quickActionComponent->create(*quickActionIncubator, qmlContext(m_quickActionComponent)); m_quickActionComponent->create(*quickActionIncubator, qmlContext(m_quickActionComponent));
m_quickActionIncubating = true; m_quickActionIncubating = true;
} else if (m_quickActionItem && !m_hovered && !m_quickActionItem->property("reacting").toBool()) { } else if (m_quickActionItem && !m_hovered && !m_quickActionItem->property("reacting").toBool()) {

View File

@@ -126,6 +126,7 @@ class MessageDelegateBase : public TimelineDelegate
public: public:
MessageDelegateBase(QQuickItem *parent = nullptr); MessageDelegateBase(QQuickItem *parent = nullptr);
~MessageDelegateBase();
NeochatRoomMember *author() const; NeochatRoomMember *author() const;
void setAuthor(NeochatRoomMember *author); void setAuthor(NeochatRoomMember *author);
@@ -193,6 +194,8 @@ private:
bool m_isThreaded = false; bool m_isThreaded = false;
std::vector<MessageObjectIncubator *> m_activeIncubators;
QPointer<QQmlComponent> m_avatarComponent; QPointer<QQmlComponent> m_avatarComponent;
bool m_avatarIncubating = false; bool m_avatarIncubating = false;
QPointer<QQuickItem> m_avatarItem; QPointer<QQuickItem> m_avatarItem;