Bug 492584

Summary: Launching application without .desktop file results in short freeze
Product: [Plasma] kwin Reporter: julusp
Component: coreAssignee: KWin default assignee <kwin-bugs-null>
Status: RESOLVED FIXED    
Severity: normal CC: julusp, madLyfe, nate, pavel23dob, xaver.hugl
Priority: NOR    
Version: 6.1.3   
Target Milestone: ---   
Platform: Other   
OS: Linux   
Latest Commit: Version Fixed In: 6.2.0
Sentry Crash Report:
Attachments: Window::iconFromDesktopFile returns only .desktop file

Description julusp 2024-09-03 10:14:10 UTC
SUMMARY
Launching application from Dolphin without having .desktop file results in parsing the application by kwin. producing following logs for every single line of executable file:

kwin_wayland[3242]: kf.config.core: "KConfigIni: In file /home/julus/factorio/bin/x64/factorio, line 28857:" Invalid entry (missing '=')

This also causes KDE to completely freeze for few seconds depending on executable filesize.

creating empty .desktop file with the app filename in app folder fixes the issue.

STEPS TO REPRODUCE
1. Launch application without having .desktop file

OBSERVED RESULT
System hangs for few seconds dependig on executable size.

EXPECTED RESULT
No KDE freeze, no parsing of the application data as desktop file

SOFTWARE/OS VERSIONS
Linux/KDE Plasma: Nobara OS
KDE Plasma Version: 6.1.3
KDE Frameworks Version: 6.5.0
Qt Version: qt6 6.7.2

ADDITIONAL INFORMATION
Occurs only via Dolphin. Running app from console or Konqueror does not result in this issue. Issue took place after upgrading from 6.0.5 to 6.1.3

perf showed the kwin as most likely responsible, most of the time by perf was spent in:
KWin::XdgActivationV1Integration::requestToken(bool, KWin::SurfaceInterface*, unsigned int, KWin::SeatInterface*, QString const&)
KDesktopFile::KDesktopFile(QStandardPaths::StandardLocation, QString const&)

per strace of kwin_wayland, the issue started immediately failure search for .desktop and opening application directly, producing the error messages.
snip (as I was stracing, the issue caused system to hang for much longer, basically for the whole duration of the sendmsg():
10:40:09.515383 access("/home/julus/factorio/bin/x64/factorio.desktop", F_OK) = -1 ENOENT (No such file or directory) 
...
10:40:09.515977 openat(AT_FDCWD, "/home/julus/factorio/bin/x64/factorio", O_RDONLY|O_CLOEXEC) = 247 <0.000011>
...
10:40:09.627286 sendmsg(15, {msg_name={sa_family=AF_UNIX, sun_path="/run/systemd/journal/socket"}, msg_namelen=30, msg_iov=[{iov_base="MESSAGE=kf.config.core: \"KConfig"..., 
...
10:40:31.243019 sendmsg(15, {msg_name={sa_family=AF_UNIX, sun_path="/run/systemd/journal/socket"}, msg_namelen=30, msg_iov=[{iov_base="MESSAGE=kf.config.core: \"KConfig"...,
/snip
Comment 1 julusp 2024-09-03 18:35:50 UTC
If I am reading source properly, the fault seems to be in XdgActivationV1Integration::requestToken() in xdgactivationv1.cpp:
Particulary following code:

QString XdgActivationV1Integration::requestToken(bool isPrivileged, SurfaceInterface *surface, uint serial, SeatInterface *seat, const QString &appId)
{
...
    if (const QString desktopFilePath = Window::findDesktopFile(appId); !desktopFilePath.isEmpty()) {
        KDesktopFile df(desktopFilePath);
        Window *window = Workspace::self()->activeWindow();
        if (!window || appId != window->desktopFileName()) {
            const auto desktop = df.desktopGroup();
            showNotify = desktop.readEntry("X-KDE-StartupNotify", desktop.readEntry("StartupNotify", true));
        }
        icon = QIcon::fromTheme(df.readIcon(), icon);
    }
...
}

The Window::findDesktopFile(appId) returns .desktop file if it exists, otherwise returns application filepath. However no further check if it is actual desktop file is made and KDesktopFile object is created with the non-desktop file and accessed as such which triggers parsing of binary file.

This would explain why creating even empty .desktop file for the app fixes the issue, however I am not sure why I did not encountered the issue until now as the code seems to be several years old. Possibly there are new ways to reach this execution path in the recent KDE version? Nevertheless this appears to be genuine bug as binary file is handled like .desktop file.
Comment 2 Zamundaaa 2024-09-05 14:41:43 UTC
Good investigation!

> This would explain why creating even empty .desktop file for the app fixes the issue, however I am not sure why I did not encountered the issue until now as the code seems to be several years old. Possibly there are new ways to reach this execution path in the recent KDE version?
Not sure either, maybe there were some changes in KDesktopFile or KConfig that made the issue worse.

Anyways, do you want to make a MR to fix this, or should I do it? Replacing the isEmpty() check with KDesktopFile::isDesktopFile should be enough to fix it afaict
Comment 3 julusp 2024-09-05 18:03:09 UTC
Created attachment 173356 [details]
Window::iconFromDesktopFile returns only .desktop file

>> Anyways, do you want to make a MR to fix this, or should I do it? Replacing the isEmpty() check with KDesktopFile::isDesktopFile should be enough to fix it afaict

Just to be sure, I've checked the other places where Window::findDesktopFile is used, and there is one other place where similar/same bug might be triggered - Window::iconFromDesktopFile which is called either by X11Window::getIcons and WaylandWindow::updateIcon

QString Window::iconFromDesktopFile(const QString &desktopFileName)
{
    const QString absolutePath = findDesktopFile(desktopFileName);
    if (absolutePath.isEmpty()) {
        return {};
    }

    KDesktopFile df(absolutePath);
    return df.readIcon();
}

As such, wouldn't be better to correct Window::findDesktopFile behavior to make sure only proper .desktop file or empty string? This way it would also help any new code in the future using this function to expect proper data. Something like attached diff (it just simply does the same check as KDesktopFile::isDesktopFile before returning)
Comment 4 Bug Janitor Service 2024-09-18 15:00:23 UTC
A possibly relevant merge request was started @ https://invent.kde.org/plasma/kwin/-/merge_requests/6418
Comment 5 Vlad Zahorodnii 2024-09-19 11:47:50 UTC
Git commit f3f2a338d42c18fe2ad8d8175eb2328501be4d51 by Vlad Zahorodnii.
Committed on 19/09/2024 at 11:35.
Pushed by vladz into branch 'master'.

Locate desktop files more carefully

It may happen that the specified app id is a file path to a binary file.
In which case, the findDesktopFile() function will return that file path
and KConfig will try to parse a binary file.

On other hand, the findDesktopFile() function should ideally always
append the ".desktop" suffix. If there's no file with such a file name,
nothing should be returned. But due to some Qt applications providing app
ids with the ".desktop" suffix, the findDesktopFile() function also tries
to find a desktop file without appending the ".desktop" suffix. However,
the fallback code doesn't actually try to verify that the desktop file
name contains the ".desktop" suffix, which can result in the
findDesktopFile() function providing values that it shouldn't. In this
case, returning the file path to a binary executable.

M  +19   -12   src/window.cpp

https://invent.kde.org/plasma/kwin/-/commit/f3f2a338d42c18fe2ad8d8175eb2328501be4d51
Comment 6 Vlad Zahorodnii 2024-09-19 12:04:14 UTC
Git commit 7797f2b22d76ec8c07e4003bc88c335215a63710 by Vlad Zahorodnii.
Committed on 19/09/2024 at 11:50.
Pushed by vladz into branch 'Plasma/6.2'.

Locate desktop files more carefully

It may happen that the specified app id is a file path to a binary file.
In which case, the findDesktopFile() function will return that file path
and KConfig will try to parse a binary file.

On other hand, the findDesktopFile() function should ideally always
append the ".desktop" suffix. If there's no file with such a file name,
nothing should be returned. But due to some Qt applications providing app
ids with the ".desktop" suffix, the findDesktopFile() function also tries
to find a desktop file without appending the ".desktop" suffix. However,
the fallback code doesn't actually try to verify that the desktop file
name contains the ".desktop" suffix, which can result in the
findDesktopFile() function providing values that it shouldn't. In this
case, returning the file path to a binary executable.


(cherry picked from commit f3f2a338d42c18fe2ad8d8175eb2328501be4d51)

Co-authored-by: Vlad Zahorodnii <vlad.zahorodnii@kde.org>

M  +19   -12   src/window.cpp

https://invent.kde.org/plasma/kwin/-/commit/7797f2b22d76ec8c07e4003bc88c335215a63710
Comment 7 Pavel Dobiáš 2024-10-10 18:40:16 UTC
*** Bug 492009 has been marked as a duplicate of this bug. ***