Bug 520065 - plasmashell crashes in TaskManager::TaskGroupingProxyModel::Private::sourceDataChanged when switching activities with Pager in a panel
Summary: plasmashell crashes in TaskManager::TaskGroupingProxyModel::Private::sourceDa...
Status: RESOLVED FIXED
Alias: None
Product: plasmashell
Classification: Plasma
Component: generic-crash (other bugs)
Version First Reported In: 6.6.4
Platform: Neon Linux
: NOR crash
Target Milestone: 1.0
Assignee: Plasma Bugs List
URL:
Keywords: drkonqi
Depends on:
Blocks:
 
Reported: 2026-05-12 10:33 UTC by Matthias Kretz
Modified: 2026-05-15 16:06 UTC (History)
4 users (show)

See Also:
Latest Commit:
Version Fixed/Implemented In: 6.6.6
Sentry Crash Report:


Attachments
New crash information added by DrKonqi (94.61 KB, text/plain)
2026-05-12 10:33 UTC, Matthias Kretz
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Kretz 2026-05-12 10:33:50 UTC
Application: plasmashell (6.6.4)

ApplicationNotResponding [ANR]: false
Qt Version: 6.10.2
Frameworks Version: 6.26.0
Operating System: Linux 6.17.0-23-generic x86_64
Windowing System: Wayland
Distribution: KDE neon User Edition
DrKonqi: 6.6.4 [CoredumpBackend]

-- Information about the crash:
I have a dual-monitor setup. When only one monitor is active I did not experience any crash.
Both monitors have a full panel on the bottom. Removing the "Icons and Text-Task Manger" applets from both panels does not resolve it.
I have now removed the widget "Pager" from both panels and now it seems to be stable. I use a single Desktop and 7 activities.

The crash can be reproduced every time.

-- Backtrace (Reduced):
#6  __pthread_kill_implementation (no_tid=0, signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:44
#7  __pthread_kill_internal (signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:78
#8  __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#9  0x00007abde9e4527e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#10 0x00007abde9e288ff in __GI_abort () at ./stdlib/abort.c:79
#11 0x00007abdeab61a31 in qAbort () at /workspace/build/src/corelib/global/qassert.cpp:46
#12 qt_maybe_message_fatal<QString&> (message=..., context=<optimized out>, msgType=QtFatalMsg) at /workspace/build/src/corelib/global/qlogging.cpp:2166
[...]
#14 0x00007abdeab63310 in QMessageLogger::fatal (this=<optimized out>, msg=0x7abdea875c00 "ASSERT: \"%s\" in file %s, line %d") at /workspace/build/src/corelib/global/qlogging.cpp:901
#15 0x00007abdeab4dc11 in qt_assert (assertion=<optimized out>, file=<optimized out>, line=<optimized out>) at /workspace/build/src/corelib/global/qassert.cpp:113
#16 0x00007abdc4ea2974 in TaskManager::TaskGroupingProxyModel::Private::sourceDataChanged (this=0x5e5b88acba00, topLeft=..., bottomRight=..., roles=...) at /workspace/build/libtaskmanager/taskgroupingproxymodel.cpp:209
#17 0x00007abdc4eb6ba2 in std::__invoke_impl<void, void (TaskManager::TaskGroupingProxyModel::Private::*&)(QModelIndex, QModelIndex, QList<int> const&), TaskManager::TaskGroupingProxyModel::Private*&, QModelIndex const&, QModelIndex const&, QList<int> const&> (__f=@0x5e5b88acebe0: (void (TaskManager::TaskGroupingProxyModel::Private::*)(class TaskManager::TaskGroupingProxyModel::Private * const, class QModelIndex, class QModelIndex, const class QList<int> &)) 0x7abdc4ea2866 <TaskManager::TaskGroupingProxyModel::Private::sourceDataChanged(QModelIndex, QModelIndex, QList<int> const&)>, __t=@0x5e5b88acebf0: 0x5e5b88acba00) at /usr/include/c++/13/bits/invoke.h:74
#18 0x00007abdc4eb6495 in std::__invoke<void (TaskManager::TaskGroupingProxyModel::Private::*&)(QModelIndex, QModelIndex, QList<int> const&), TaskManager::TaskGroupingProxyModel::Private*&, QModelIndex const&, QModelIndex const&, QList<int> const&> (__fn=@0x5e5b88acebe0: (void (TaskManager::TaskGroupingProxyModel::Private::*)(class TaskManager::TaskGroupingProxyModel::Private * const, class QModelIndex, class QModelIndex, const class QList<int> &)) 0x7abdc4ea2866 <TaskManager::TaskGroupingProxyModel::Private::sourceDataChanged(QModelIndex, QModelIndex, QList<int> const&)>) at /usr/include/c++/13/bits/invoke.h:96
#19 0x00007abdc4eb5e69 in std::_Bind<void (TaskManager::TaskGroupingProxyModel::Private::*(TaskManager::TaskGroupingProxyModel::Private*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(QModelIndex, QModelIndex, QList<int> const&)>::__call<void, QModelIndex const&, QModelIndex const&, QList<int> const&, 0ul, 1ul, 2ul, 3ul>(std::tuple<QModelIndex const&, QModelIndex const&, QList<int> const&>&&, std::_Index_tuple<0ul, 1ul, 2ul, 3ul>) (this=0x5e5b88acebe0, __args=...) at /usr/include/c++/13/functional:506
#20 0x00007abdc4eb57a4 in std::_Bind<void (TaskManager::TaskGroupingProxyModel::Private::*(TaskManager::TaskGroupingProxyModel::Private*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(QModelIndex, QModelIndex, QList<int> const&)>::operator()<QModelIndex const&, QModelIndex const&, QList<int> const&, void>(QModelIndex const&, QModelIndex const&, QList<int> const&) (this=0x5e5b88acebe0) at /usr/include/c++/13/functional:591
#21 0x00007abdc4eb502d in QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul, 1ul, 2ul>, QtPrivate::List<QModelIndex const&, QModelIndex const&, QList<int> const&>, void, std::_Bind<void (TaskManager::TaskGroupingProxyModel::Private::*(TaskManager::TaskGroupingProxyModel::Private*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(QModelIndex, QModelIndex, QList<int> const&)> >::call(std::_Bind<void (TaskManager::TaskGroupingProxyModel::Private::*(TaskManager::TaskGroupingProxyModel::Private*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(QModelIndex, QModelIndex, QList<int> const&)>&, void**)::{lambda()#1}::operator()() const (__closure=0x7ffd142eae80) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:116
#22 0x00007abdc4eb57ea in QtPrivate::FunctorCallBase::call_internal<void, QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul, 1ul, 2ul>, QtPrivate::List<QModelIndex const&, QModelIndex const&, QList<int> const&>, void, std::_Bind<void (TaskManager::TaskGroupingProxyModel::Private::*(TaskManager::TaskGroupingProxyModel::Private*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(QModelIndex, QModelIndex, QList<int> const&)> >::call(std::_Bind<void (TaskManager::TaskGroupingProxyModel::Private::*(TaskManager::TaskGroupingProxyModel::Private*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(QModelIndex, QModelIndex, QList<int> const&)>&, void**)::{lambda()#1}>(void**, QtPrivate::FunctorCall<std::integer_sequence<unsigned long, 0ul, 1ul, 2ul>, QtPrivate::List<QModelIndex const&, QModelIndex const&, QList<int> const&>, void, std::_Bind<void (TaskManager::TaskGroupingProxyModel::Private::*(TaskManager::TaskGroupingProxyModel::Private*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(QModelIndex, QModelIndex, QList<int> const&)> >::call(std::_Bind<void (TaskManager::TaskGroupingProxyModel::Private::*(TaskManager::TaskGroupingProxyModel::Private*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(QModelIndex, QModelIndex, QList<int> const&)>&, void**)::{lambda()#1}&&) (args=0x7ffd142eb010, fn=...) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:65


Reported using DrKonqi
Comment 1 Matthias Kretz 2026-05-12 10:33:51 UTC
Created attachment 192222 [details]
New crash information added by DrKonqi

DrKonqi auto-attaching complete backtrace.
Comment 2 TraceyC 2026-05-12 19:46:41 UTC
I'm not able to reproduce this in Plasma built from git-master or Plasma 6.6.4 on Solus.

- Laptop connected to an external monitor, making 2 displays active
- Panel with a pager widget and other widgets on the laptop
- Default panel on the monitor, which also has a pager widget

I'll leave this open so others can try to reproduce
Comment 3 David Edmundson 2026-05-13 07:56:13 UTC
It's an assert rather than a crash, I have no idea why Neon builds with asserts on for non-developer setups.

The good news is we used to have a crash there and at least we finally found out what's causing it.

tasksmodel.cpp:290

    QObject::connect(groupingProxyModel, &QAbstractItemModel::rowsInserted, q, [this](const QModelIndex &parent, int first, int last) {

ends up calling                         Q_EMIT filterProxyModel->dataChanged(filterIndex, filterIndex);

but we're still inside the groupingProxyModel::rowsInserted so our state isn't settled.

It's super weird for a model to be emitting dataChanged for source model in a tree.


---

We probably could just turn my assert into a comment explaining what's happening.
Comment 4 Marco Martin 2026-05-13 08:51:56 UTC
(In reply to David Edmundson from comment #3)
> It's super weird for a model to be emitting dataChanged for source model in
> a tree.

So, if i understand correctly, is 
* groupingProxyModel has filterProxyModel as its source
* groupingProxyModel has a new row inserted
* if the new row is a startup or a launcher, searcg it in the... source model and emits a datachanged there?

> We probably could just turn my assert into a comment explaining what's
> happening.

probably.. we could also check on that side whether the index is valid
Comment 5 David Edmundson 2026-05-13 09:04:05 UTC
>probably.. we could also check on that side whether the index is valid

See be417b4d3d0f5e6eb3c9c0f492aa031bc0d2d4d8 which I think is the crash fix.


I put the debug in to work out why we got a dataChanged from an index we couldn't map, which starts to make sense if we're in some re-entrant situation.
Comment 6 Bug Janitor Service 2026-05-13 09:43:09 UTC
A possibly relevant merge request was started @ https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/6581
Comment 7 Marco Martin 2026-05-14 12:14:26 UTC
Git commit 919a8a92a5c3437f6406a0970c548ecf7100e439 by Marco Martin.
Committed on 14/05/2026 at 12:14.
Pushed by mart into branch 'master'.

Libtaskmanager: invalidate filter on source row insertion

When a source row is inserted, is possible it's a row we have either
a launcher or a startup entry existing, which will now need to be
filtered out. previously it was emitting dataChanged on the source
launcher or startup task, causing then a reevaluation of the filter.
But since we still were in the rowsInserted handler, the state
might have not been settled yet, so
TaskManager::TaskGroupingProxyModel::Private::sourceDataChanged
could find itself with an invalid source index, triggering an assert.

Instead simply call invalidateFilter, which will cause all the
filterAcceptsRow to be called again at the right moment.
It is a bit more inefficient as the row iteration will be done for
each entry instead of only as many times as there are new rows,
but should be much safer.

### Test plan

launch an app, the startup task should still change immediately to
the "real" one as soon the window appears without the task being
duplicated for a split second. same thing when starting a task from a
launcher.

### Bugs fixed

M  +4    -33   libtaskmanager/tasksmodel.cpp

https://invent.kde.org/plasma/plasma-workspace/-/commit/919a8a92a5c3437f6406a0970c548ecf7100e439
Comment 8 Marco Martin 2026-05-14 12:15:14 UTC
Git commit ddc45b08e9a536e36933292f0e68f8e495b64668 by Marco Martin.
Committed on 14/05/2026 at 12:14.
Pushed by mart into branch 'Plasma/6.7'.

Libtaskmanager: invalidate filter on source row insertion

When a source row is inserted, is possible it's a row we have either
a launcher or a startup entry existing, which will now need to be
filtered out. previously it was emitting dataChanged on the source
launcher or startup task, causing then a reevaluation of the filter.
But since we still were in the rowsInserted handler, the state
might have not been settled yet, so
TaskManager::TaskGroupingProxyModel::Private::sourceDataChanged
could find itself with an invalid source index, triggering an assert.

Instead simply call invalidateFilter, which will cause all the
filterAcceptsRow to be called again at the right moment.
It is a bit more inefficient as the row iteration will be done for
each entry instead of only as many times as there are new rows,
but should be much safer.

### Test plan

launch an app, the startup task should still change immediately to
the "real" one as soon the window appears without the task being
duplicated for a split second. same thing when starting a task from a
launcher.

### Bugs fixed


(cherry picked from commit 919a8a92a5c3437f6406a0970c548ecf7100e439)

61c20099 Libtaskmanager: invalidate filter on source row insertion

Co-authored-by: Marco Martin <notmart@gmail.com>

M  +4    -33   libtaskmanager/tasksmodel.cpp

https://invent.kde.org/plasma/plasma-workspace/-/commit/ddc45b08e9a536e36933292f0e68f8e495b64668
Comment 9 Marco Martin 2026-05-14 12:16:00 UTC
Git commit 1b4a83f48bff48a64166f21528675bd7455fc539 by Marco Martin.
Committed on 14/05/2026 at 12:15.
Pushed by mart into branch 'Plasma/6.6'.

Libtaskmanager: invalidate filter on source row insertion

When a source row is inserted, is possible it's a row we have either
a launcher or a startup entry existing, which will now need to be
filtered out. previously it was emitting dataChanged on the source
launcher or startup task, causing then a reevaluation of the filter.
But since we still were in the rowsInserted handler, the state
might have not been settled yet, so
TaskManager::TaskGroupingProxyModel::Private::sourceDataChanged
could find itself with an invalid source index, triggering an assert.

Instead simply call invalidateFilter, which will cause all the
filterAcceptsRow to be called again at the right moment.
It is a bit more inefficient as the row iteration will be done for
each entry instead of only as many times as there are new rows,
but should be much safer.

### Test plan

launch an app, the startup task should still change immediately to
the "real" one as soon the window appears without the task being
duplicated for a split second. same thing when starting a task from a
launcher.

### Bugs fixed


(cherry picked from commit 919a8a92a5c3437f6406a0970c548ecf7100e439)

61c20099 Libtaskmanager: invalidate filter on source row insertion

Co-authored-by: Marco Martin <notmart@gmail.com>

M  +4    -33   libtaskmanager/tasksmodel.cpp

https://invent.kde.org/plasma/plasma-workspace/-/commit/1b4a83f48bff48a64166f21528675bd7455fc539