Bug 493797

Summary: screen freezes due to kwin_x11 stuck in infinite loop
Product: [Plasma] kwin Reporter: acmondor <bugs.kde>
Component: X11 IntegrationAssignee: KWin default assignee <kwin-bugs-null>
Status: REPORTED ---    
Severity: crash    
Priority: NOR    
Version: 6.1.5   
Target Milestone: ---   
Platform: Gentoo Packages   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:
Attachments: gdb backtrace
qdbus6 org.kde.KWin /KWin supportInformation

Description acmondor 2024-09-28 22:09:13 UTC
Created attachment 174180 [details]
gdb backtrace

SUMMARY

Since switching to plasma 6 I observed the entire screen freezing, except for the mouse which can still be moved
around on the screen but it has the hand icon (ie that used for move) and it can't be used to click on anything.
Also, when the screen is frozen, kwin_x11 is running at 100% cpu and attaching a debugger to it shows that it is
stuck in window.cpp in the for(;;) loop in the following method:

  QRectF Window::nextInteractiveMoveGeometry(const QPointF &global) const

This issue initially seemed somewhat random and was observed when opening or moving firefox near the top of the screen, but I since determined it has nothing to do with firefox and can be triggered by moving any application around
the desktop with its title bar at or near the top of the screen. I have reproduced this problem with Konsole, Kate, and KMajongg on two different systems.

The only way to recover is to kill the session via a virtual terminal or a ssh connection. A recovery can also
be done using gdb (see  ADDITIONAL INFORMATION below) to force an exit from the stuck for(;;) loop, but that's only practical if one has built kwin_x11 with debug symbols.

I have not been able to determine if the issue exists with wayland, as I currently cannot run wayland. I just
get a blank black screen when trying to run a wayland session. I also only have single monitor on my machines, so
I do not know if systems with multiple screens are affected.

I build kwin_x11 with debug symbols and attached gdb after a lockup and from what I observed it seems to be
related to a rounding error of floating point math, at least in the check that is intended to avoid such lockups:

            // Move it back
            currentTry.translate(dx, dy);
            nextMoveResizeGeom = currentTry;

            if (std::abs(currentMoveResizeGeom.left() - nextMoveResizeGeom.left()) < 1.0
                && std::abs(currentMoveResizeGeom.right() - nextMoveResizeGeom.right()) < 1.0
                && std::abs(currentMoveResizeGeom.top() - nextMoveResizeGeom.top()) < 1.0
                && std::abs(currentMoveResizeGeom.bottom() - nextMoveResizeGeom.bottom()) < 1.0) {
                break; // Prevent lockup
            }

Note rebuilding kwin_x11 with the " < 1.0" in the above code changed to " =< 1.0" avoids the issue, but has the site effect of allowing one to move an application so its title bar is mostly beyond the top of the screen. Perhaps that's the purpose of the nextInteractiveMoveGeometry (ie keeping the title bar visible)?


STEPS TO REPRODUCE
1. To get the screen to freeze one just needs to quickly move an application (eg Konsole) around the desktop with its title
bar at or near the top of the screen. I can usually create a lockup in less than a minute. I sometimes have to grab and release the title bar of the application mutiple times and time grab the title bar at a different location. Sometimes resizing the window helps too. When the freeze occurs the window will no longer move and the mouse icon won't change when the mouse is released. If the system doesn't seem to want to freeze up, try opening a second instance of the application taking turns moving both of them around at the top of the screen.


OBSERVED RESULT
Desktop freezes

EXPECTED RESULT
Desktop should not freeze, regardless of how/where an application is moved around on the screen.

SOFTWARE/OS VERSIONS
Windows: 
macOS: 
(available in the Info Center app, or by running `kinfo` in a terminal window)
Linux/KDE Plasma: Gentoo
KDE Plasma Version: 6.1.5
KDE Frameworks Version: 6.5.0
Qt Version: 6.7.2
Kernel 6.6.52  x86_64

ADDITIONAL INFORMATION

Steps used to debug the issue:

1) Build kwin with debug symbols and install that on the test system

2) Cause the screen to freeze as mentioned above

3) From another machine ssh to the frozen system and attach gdb to the kwin_x11 process:

    gdb /usr/bin/kwin_x11 $(pidof kwin_x11)


4) Set a break point in Window::nextInteractiveMoveGeometry for "nextMoveResizeGeom = currentTry;" (should be window.cpp:1714), that is the line before the if statement mentioned above (ie one intended to prevent lockups):

    b window.cpp:1714

5) continue until breakpoint hit:

    continue

6) run the following to monitor some key values:
   display currentMoveResizeGeom
   display nextMoveResizeGeom
   display currentTry
   
7) do another loop:

    continue

8) observe the displayed values, will be something like the following:
    1: currentMoveResizeGeom = {xp = 124, yp = 0, w = 1086, h = 749}
    2: nextMoveResizeGeom = {xp = 124, yp = -0.99999999999999822, w = 1086, h = 749}
    3: currentTry = {xp = 124, yp = -0.99999999999999822, w = 1086, h = 749}

9) repeat 7 & 8 as needed and notice the displayed values never change and hence there is no way for the
   code to get out of the for(;;) loop

10) to force an exit from the for(;;) loop and recover from the lockup do the following:

   next                                                     (step over "nextMoveResizeGeom = currentTry;") 
   delete                                                  (remove all breakpoints)
   return nextMoveResizeGeom        (get out of stuck for(;;) loop, ignore the warning about function's return value)
   continue                                             (allow the app to run. one can also exit gdb with 'quit')

11) observe that the screen on the test system is working again
Comment 1 acmondor 2024-09-28 22:10:41 UTC
Created attachment 174181 [details]
qdbus6 org.kde.KWin /KWin supportInformation