https://bugs.kde.org/show_bug.cgi?id=472862

--- Comment #14 from Harald Sitter <sit...@kde.org> ---
I've found a way to make plasma crash like this:

- open krunner kcm
- enable kate session (this creates a kdirwatch)
- disable kate session (this deletes the kdirwatch)
- open kate and save a session
- crash

What appears to happen for plasma is incredibly stupid but at first glance hard
to solve. KRunner (the framework) gives every runner a thread, it does this by
creating the runner on the current thread and then moveToThread()s it to the
target thread. Inside the konsoleprofile and katesession runner implementations
we create a KDirWatch.

Now because of how kdirwatch works things get complicated.
Multiple "fronting" kdirwatch objects may point to the same internal private
instance that actually encapsulates the watching logic. This is so we can
install 300 kdirwatches on plasmarc but in the end only a single inotify watch
is used to back all those fronting objects.
Things fall over because the backing objects are managed thread-local e.g. if I
have two threads and each have watches on plasmarc it in fact uses two private
instances and two inotify instances (one per thread). This then gets in the way
of moveToThread because moving a KDirWatch from thread0 to thread1 means a
KDirWatch living in thread1 now points to a KDirWatchPrivate instance in
thread0.
Specifically the crash appears because of use-after-destruction...

The destructor has a check for dwp_self.hasLocalData() (that's the thread-local
backing data)
https://invent.kde.org/frameworks/kcoreaddons/-/blob/80b6893d85bc90fb5d82882c41caa171748c1c63/src/lib/io/kdirwatch.cpp#L1895

this will evaluate to false because we never constructed a private on this
thread (the private is on the original thread)
https://invent.kde.org/frameworks/kcoreaddons/-/blob/80b6893d85bc90fb5d82882c41caa171748c1c63/src/lib/io/kdirwatch.cpp#L85

this then means the refcount on thread0 is off because we don't unref in the
destructor and the end result is that we have a "Client" record that points to
an instance (that is the pubic KDirWatch) that no longer exists 
https://invent.kde.org/frameworks/kcoreaddons/-/blob/80b6893d85bc90fb5d82882c41caa171748c1c63/src/lib/io/kdirwatch.cpp#L1401

and there is our crash. When the thread-local private in thread0 now receives
an event pertaining to the since-deleted KDirWatch that was moved to thread1 it
will crash on a bogus pointer.

Supposedly we could just change the if in the destructor to always unref when
there is a d regardless of thread-local data. I currently cannot conceive of a
scenario where unrefing should be skipped when a d is available.

Mind you, I don't understand how kwin_wayland would end up in that particular
hell, as I can only see it using KDirWatch::self which shouldn't have this
problem.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to