kate: fix use-after-free crash in setupGhostProvider
m_ghost was parented to the view, so Qt parent-child cleanup could destroy it when a view was replaced. The raw pointer remained non-null, causing a double-free on the next viewChanged signal. Fix by using QPointer<OllieGhostProvider> which auto-nulls on destroy. Also replace qobject_cast with dynamic_cast for KF5 KTextEditor interfaces to avoid crashes when qt_metacast accesses uninitialized KateViewConfig during early view activation.
This commit is contained in:
parent
5d18806ad6
commit
455d9c9190
|
|
@ -106,7 +106,10 @@ OllieGhostProvider::OllieGhostProvider(KTextEditor::View *view, QDBusInterface *
|
|||
#if KTEXTEDITOR_VERSION_MAJOR >= 6
|
||||
view->registerInlineNoteProvider(this);
|
||||
#else
|
||||
auto *noteIface = qobject_cast<KTextEditor::InlineNoteInterface *>(view);
|
||||
// Use dynamic_cast instead of qobject_cast: during view construction,
|
||||
// qt_metacast() can access uninitialized KateViewConfig and crash.
|
||||
// dynamic_cast only needs the vtable which is valid once the C++ ctor runs.
|
||||
auto *noteIface = dynamic_cast<KTextEditor::InlineNoteInterface *>(view);
|
||||
if (noteIface)
|
||||
noteIface->registerInlineNoteProvider(this);
|
||||
#endif
|
||||
|
|
@ -120,7 +123,7 @@ OllieGhostProvider::~OllieGhostProvider()
|
|||
#if KTEXTEDITOR_VERSION_MAJOR >= 6
|
||||
m_view->unregisterInlineNoteProvider(this);
|
||||
#else
|
||||
auto *iface = qobject_cast<KTextEditor::InlineNoteInterface *>(m_view);
|
||||
auto *iface = dynamic_cast<KTextEditor::InlineNoteInterface *>(m_view);
|
||||
if (iface)
|
||||
iface->unregisterInlineNoteProvider(this);
|
||||
#endif
|
||||
|
|
@ -257,7 +260,7 @@ void OllieGhostProvider::onCursorPositionChanged()
|
|||
if (m_view->isCompletionActive())
|
||||
return;
|
||||
#else
|
||||
auto *ccIface = qobject_cast<KTextEditor::CodeCompletionInterface *>(m_view);
|
||||
auto *ccIface = dynamic_cast<KTextEditor::CodeCompletionInterface *>(m_view);
|
||||
if (ccIface && ccIface->isCompletionActive())
|
||||
return;
|
||||
#endif
|
||||
|
|
@ -380,7 +383,7 @@ void OllieGhostProvider::showOverlay()
|
|||
QFont font = m_view->configValue(QStringLiteral("font")).value<QFont>();
|
||||
#else
|
||||
QFont font;
|
||||
auto *cfgIface = qobject_cast<KTextEditor::ConfigInterface *>(m_view);
|
||||
auto *cfgIface = dynamic_cast<KTextEditor::ConfigInterface *>(m_view);
|
||||
if (cfgIface)
|
||||
font = cfgIface->configValue(QStringLiteral("font")).value<QFont>();
|
||||
else
|
||||
|
|
|
|||
|
|
@ -749,7 +749,7 @@ bool OllieKateView::eventFilter(QObject *obj, QEvent *event)
|
|||
(activeView && activeView->isCompletionActive()))
|
||||
return QObject::eventFilter(obj, event);
|
||||
#else
|
||||
auto *ccIface = activeView ? qobject_cast<KTextEditor::CodeCompletionInterface *>(activeView) : nullptr;
|
||||
auto *ccIface = activeView ? dynamic_cast<KTextEditor::CodeCompletionInterface *>(activeView) : nullptr;
|
||||
if (QApplication::activePopupWidget() ||
|
||||
(ccIface && ccIface->isCompletionActive()))
|
||||
return QObject::eventFilter(obj, event);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusConnection>
|
||||
#include <QPointer>
|
||||
#include <QTextEdit>
|
||||
#include <QLineEdit>
|
||||
#include <QLabel>
|
||||
|
|
@ -109,7 +110,7 @@ private:
|
|||
QString m_sessionId;
|
||||
qlonglong m_chatOffset = 0;
|
||||
|
||||
OllieGhostProvider *m_ghost = nullptr;
|
||||
QPointer<OllieGhostProvider> m_ghost;
|
||||
bool m_ghostPrefix = false; // true after Meta+O, waiting for second key
|
||||
|
||||
QString projectBaseDir();
|
||||
|
|
|
|||
Reference in New Issue