fix: remove app event filters on view destruction (crash on plugin reload)

The acme, palette, radial, and switch views each call
qApp->installEventFilter(this) but never removed it. QObject only auto-removes
event filters installed *on itself*, not filters it installed on *another*
object (here qApp). So when a plugin .so is unloaded/reloaded — e.g. reinstalling
the plugin — the view is destroyed while qApp still holds a dangling pointer to
it in its filter list, and the next dispatched event calls into freed memory:

  QCoreApplicationPrivate::sendThroughApplicationEventFilters -> SIGSEGV

Add qApp->removeEventFilter(this) to each view destructor (giving AcmeView a real
dtor body instead of =default). 18/18 ctest green.
This commit is contained in:
Levi Neely 2026-10-09 10:56:52 +02:00
parent 67e8d53827
commit 629a2da68d
4 changed files with 19 additions and 1 deletions

View File

@ -193,7 +193,13 @@ AcmeView::AcmeView(AcmePlugin *plugin, KTextEditor::MainWindow *mainWindow)
qApp->installEventFilter(this);
}
AcmeView::~AcmeView() = default;
AcmeView::~AcmeView()
{
// Remove the application event filter we installed on qApp; QObject only
// auto-removes filters installed on itself. Without this, a plugin
// unload/reload leaves qApp with a dangling filter pointer -> crash.
qApp->removeEventFilter(this);
}
QAction *AcmeView::findActionByName(const QString &nameOrText) const
{

View File

@ -124,6 +124,10 @@ PaletteView::PaletteView(PalettePlugin *plugin, KTextEditor::MainWindow *mainWin
PaletteView::~PaletteView()
{
// We installed this on qApp; QObject only auto-removes filters installed on
// itself, so remove ours explicitly. Otherwise, on plugin unload/reload
// qApp keeps a dangling filter pointer and the next event crashes.
qApp->removeEventFilter(this);
delete m_palette;
}

View File

@ -83,6 +83,10 @@ RadialView::RadialView(RadialPlugin *plugin, KTextEditor::MainWindow *mainWindow
RadialView::~RadialView()
{
// Remove the application event filter we installed on qApp; QObject only
// auto-removes filters installed on itself. Without this, a plugin
// unload/reload leaves qApp with a dangling filter pointer -> crash.
qApp->removeEventFilter(this);
delete m_radial;
}

View File

@ -143,6 +143,10 @@ SwitchView::SwitchView(SwitchPlugin *plugin, KTextEditor::MainWindow *mainWindow
SwitchView::~SwitchView()
{
// Remove the application event filter we installed on qApp; QObject only
// auto-removes filters installed on itself. Without this, a plugin
// unload/reload leaves qApp with a dangling filter pointer -> crash.
qApp->removeEventFilter(this);
delete m_filePalette;
delete m_symbolPalette;
}