#1107954 xfwm4: crashes on ALT+TAB windows switching

Package:
xfwm4
Source:
xfwm4
Description:
window manager of the Xfce project
Submitter:
Adam Chyła
Date:
2025-06-21 07:37:02 UTC
Severity:
normal
Tags:
#1107954#5
Date:
2025-06-17 21:43:48 UTC
From:
To:
Dear maintainer,

xfwm4 crashes on switching between windows (ALT+TAB).

The workaround is to set the "Cycle through windows in a list" option in "Window
Manager Tweaks", this will use a different ALT+TAB windows view.


kernel log message:

   traps: xfwm4[1961] trap divide error ip:5616f7acfda1 sp:7ffe3769abb0 error:0 in xfwm4[5616f7a97000+3f000]


I have collected the coredump and the stack trace points createWindowlist
function, at ./src/tabwin.c:558:

   Program terminated with signal SIGFPE, Arithmetic exception.
   [...]
   (gdb) where
   #0  0x0000561b6bfd3da1 in createWindowlist (tabwin_widget=0x561b7319a270, screen_info=0x561b72fdfa00) at ./src/tabwin.c:558
   #1  tabwinCreateWidget (monitor_num=<optimized out>, screen_info=0x561b72fdfa00, tabwin=0x561b72fac000) at ./src/tabwin.c:835
   #2  tabwinCreate (client_list=client_list@entry=0x7ffd60ada298, selected=selected@entry=0x561b72eddce0, display_workspace=<optimized out>) at ./src/tabwin.c:941
   #3  0x0000561b6bfadebd in clientCycle (c=<optimized out>, event=0x561b73234e40) at ./src/cycle.c:533
   #4  0x0000561b6bfb210b in handleKeyPress (event=0x561b73234e40, display_info=0x561b72de9970) at ./src/events.c:329
   #5  handleEvent (event=<optimized out>, display_info=0x561b72de9970) at ./src/events.c:2181
   #6  xfwm4_event_filter (event=0x561b73234e40, data=0x561b72de9970) at ./src/events.c:2302
   #7  0x0000561b6bfafd80 in eventXfwmFilter (gdk_xevent=<optimized out>, gevent=<optimized out>, data=<optimized out>) at ./src/event_filter.c:175
   #8  0x00007f70b67846ff in ?? () from /lib/x86_64-linux-gnu/libgdk-3.so.0
   #9  0x00007f70b6784a54 in ?? () from /lib/x86_64-linux-gnu/libgdk-3.so.0
   #10 0x00007f70b67263b0 in gdk_display_get_event () from /lib/x86_64-linux-gnu/libgdk-3.so.0
   #11 0x00007f70b6784792 in ?? () from /lib/x86_64-linux-gnu/libgdk-3.so.0
   #12 0x00007f70b5b7b7a9 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
   #13 0x00007f70b5b7ba38 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
   #14 0x00007f70b5b7bcef in g_main_loop_run () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
   #15 0x00007f70b6008495 in gtk_main () from /lib/x86_64-linux-gnu/libgtk-3.so.0
   #16 0x0000561b6bf9db3d in main (argc=<optimized out>, argv=<optimized out>) at ./src/main.c:764


Related part of code:

   xfwm4-4.18.0/src/tabwin.c
   556         if (screen_info->params->cycle_tabwin_mode == STANDARD_ICON_GRID)
   557         {
   558             gtk_grid_attach (GTK_GRID (windowlist), GTK_WIDGET (window_button),
   559                              packpos % tabwin->grid_cols, packpos / tabwin->grid_cols,
   560                              1, 1);
   561         }


Based on the collected coredump, the value of tabwin->grid_cols is 0,
which causes a division by zero in line 559:

   (gdb) print tabwin->grid_cols
   $1 = 0


The tabwin->grid_cols is set in the function computeTabwinData, which is called
from tabwinCreateWidget:

   xfwm4-4.18.0/src/tabwin.c
   757 static TabwinWidget *
   758 tabwinCreateWidget (Tabwin *tabwin, ScreenInfo *screen_info, gint monitor_num)
   759 {
   [...]
   798     if (tabwin->icon_list == NULL)
   799     {
   800         computeTabwinData (screen_info, tabwin_widget);
   801     }


The value is calculated based on tabwin->monitor_width and size_request:

   xfwm4-4.18.0/src/tabwin.c
   639 static void
   640 computeTabwinData (ScreenInfo *screen_info, TabwinWidget *tabwin_widget)
   641 {
   [...]
   655     tabwin->monitor_width = getMinMonitorWidth (screen_info);
   [...]
   684         size_request = tabwin->icon_size + tabwin->label_height + 2 * WIN_ICON_BORDER;
   685         tabwin->grid_cols = (int) (floor ((double) tabwin->monitor_width * WIN_MAX_RATIO /
   686                                           (double) size_request));


The values of the related variables are:

   (gdb) print tabwin->icon_size
   $2 = 288
   (gdb) print tabwin->label_height
   $3 = 19
   (gdb) print size_request
   $4 = 317
   (gdb) print tabwin->monitor_width
   $5 = 103


Checking the calculations with sample app:

    1 #include <stdio.h>
    2 #include <math.h>
    3
    4 #define WIN_ICON_BORDER 5
    5 #define WIN_MAX_RATIO 0.8
    6
    7 int
    8 main() {
    9     int icon_size = 288,
   10         label_height = 19,
   11         monitor_width = 103;
   12
   13     int size_request = icon_size + label_height + 2 * WIN_ICON_BORDER;
   14     double numerator = (double) monitor_width * WIN_MAX_RATIO;
   15
   16     printf("size_request=%d\n", size_request);
   17     printf("numerator=%lf\n", numerator);
   18
   19     double divided = numerator / size_request;
   20     double divided_after_floor = floor(divided);
   21
   22     printf("divided=%lf\n", divided);
   23     printf("divided_after_floor=%lf\n", divided_after_floor);
   24     printf("final result=%d\n", (int)divided_after_floor);
   25
   26     return 0;
   27 }


Console output:

   size_request=317
   numerator=82.400000
   divided=0.259937
   divided_after_floor=0.000000
   final result=0


The monitor_width value taken from GDK functions looks suspicious; thus, it may
require further investigation under separate bug report.

I believe the root cause of the issue is not in the xfwm4 itself, but in my
opinion xfwm4 should avoid division by zero appropriately. The crash can
be prevented by setting tabwin->grid_cols to the maximum of 1 and the calculated
value:
--- a/src/tabwin.c   2022-11-01 09:53:34.000000000 +0000
+++ b/src/tabwin.c   2025-05-30 22:37:03.668696034 +0000
@@ -682,8 +682,8 @@
              tabwin->icon_size = standard_icon_size;
          }
          size_request = tabwin->icon_size + tabwin->label_height + 2 * WIN_ICON_BORDER;
-        tabwin->grid_cols = (int) (floor ((double) tabwin->monitor_width * WIN_MAX_RATIO /
-                                          (double) size_request));
+        tabwin->grid_cols = (int) fmax(1, floor ((double) tabwin->monitor_width * WIN_MAX_RATIO /
+                                                 (double) size_request));
          tabwin->grid_rows = (int) (ceil ((double) tabwin->client_count /
                                           (double) tabwin->grid_cols));

@@ -702,8 +702,8 @@
              size_request = tabwin->icon_size + tabwin->label_height + 2 * WIN_ICON_BORDER;

              /* Recalculate with new icon size */
-            tabwin->grid_cols = (int) (floor ((double) tabwin->monitor_width * WIN_MAX_RATIO /
-                                              (double) size_request));
+            tabwin->grid_cols = (int) fmax(1, floor ((double) tabwin->monitor_width * WIN_MAX_RATIO /
+                                                     (double) size_request));
              tabwin->grid_rows = (int) (ceil ((double) tabwin->client_count /
                                               (double) tabwin->grid_cols));

@@ -720,8 +720,8 @@
          tabwin->icon_size = LISTVIEW_WIN_ICON_SIZE;
          gtk_widget_style_get (GTK_WIDGET (tabwin_widget),
                                "listview-icon-size", &tabwin->icon_size, NULL);
-        tabwin->grid_rows = (int) (floor ((double) tabwin->monitor_height * WIN_MAX_RATIO /
-                                          (double) (tabwin->icon_size + 2 * WIN_ICON_BORDER)));
+        tabwin->grid_rows = (int) fmax(1, floor ((double) tabwin->monitor_height * WIN_MAX_RATIO /
+                                                 (double) (tabwin->icon_size + 2 * WIN_ICON_BORDER)));
          tabwin->grid_cols = (int) (ceil ((double) tabwin->client_count /
                                           (double) tabwin->grid_rows));
      }


Bug also exist in xfwm4_4.20.0 from Trixie, the same patch applies.

Best regards,
Adam.

#1107954#10
Date:
2025-06-20 06:59:18 UTC
From:
To:
I can't reproduce this here (on 4.20.0-1), but I guess you might be on a
specific situation on your installation leading to that division by zero (nice
job on the investigation btw).

I've added some debugging to an xfwm4 build to check my
monitor_width/monitor_height and yours are definitely suspicious:

DBG[tabwin.c:691] computeTabwinData(): tabwin->monitor_width = 1920; tabwin-

Could you report this directly upstream because while I think it might be
worth double-checking for division by zero, there's something fishy here
(maybe with GDK as you said) and I think upstream would be better to check
that.

Also not that in my case the monitor_width seems wrong (1920×1080 is the size
of my laptop display but I'm currently docked to a 3840x2160 display which
should be used for the calculation). Maybe it's something similar for you (in
case you have a smaller display attached)?

Regards,

#1107954#15
Date:
2025-06-20 19:38:52 UTC
From:
To:
Hey Yves-Alexis,

thank you for your response.


This seems to be intentional, the code selects the minimum screen width:

   xfwm4-4.18.0/src/tabwin.c
   344 static int
   345 getMinMonitorWidth (ScreenInfo *screen_info)
   346 {
   347     int i, min_width, num_monitors = myScreenGetNumMonitors (screen_info);
   348     for (min_width = i = 0; i < num_monitors; i++)
   349     {
   350         GdkRectangle monitor;
   351         xfwm_get_monitor_geometry (screen_info->gscr, i, &monitor, FALSE);
   352         if (min_width == 0 || monitor.width < min_width)
   353             min_width = monitor.width;
   354     }
   355     return min_width;
   356 }

   xfwm4-4.18.0/src/tabwin.c
   639 static void
   640 computeTabwinData (ScreenInfo *screen_info, TabwinWidget *tabwin_widget)
   641 {
   [...]
   655     tabwin->monitor_width = getMinMonitorWidth (screen_info);

Unfortunately, this is not my case. I don't have a smaller display.


Ragards,
Adam.

#1107954#20
Date:
2025-06-21 07:34:24 UTC
From:
To:
control: forwarded -1 https://gitlab.xfce.org/xfce/xfwm4/-/issues/867
Thanks!

Ah good point. Not sure why because here the laptop screen is *disabled* (so I
think shouldn't be used when calculating a size for display).
So yeah there's definitely something fishy with a monitor size of 103px. Maybe
a scaling issue (I noticed somewhere that the Scaling factor is used).

Regards,