Bug#1118780: gtk4: Mipmap tests fail 16/32-bit pixel format conversions due to memory alignment issues
Gregor Riepl
onitake at gmail.com
Sat Oct 25 12:50:54 BST 2025
Source: gtk4
Version: 4.20.2+ds-1
Severity: serious
Tags: ftbfs upstream
Justification: fails unit tests at the end of the build process
X-Debbugs-Cc: onitake at gmail.com
The gtk4 package build currently fails on architectures with strict memory alignment rules, namely sparc64.
The errors manifest as bus errors due to unaligned memory access in unit tests for mipmap conversion routines. [1]
These unit test use the helper function texture_builder_init[2], which unconditionally calls gdk_memory_layout_init[3] and gdk_memory_layout_fudge[4] with a required memory alignment of 1 byte.
gdk_memory_layout_fudge[4] will then generate a randomized memory layout for storing pixel data.
This function would actually honor a requested memory alignment, but not if the alignment is always 1.
With a requested alignment of 1, it may generate data offsets that cause errors when accessing 16- or 32-bit pixel formats, which must be aligned at 2 or 4 byte boundaries on sparc64.
I can see several possible fixes for this issue:
1. Always enforce the minimum required alignment based on the underlying data types. This is the most drastic change and will require modifying gdk_memory_layout_init.[2]
2. Enforce the minimum required alignment only on CPU architectures that require it. This would fix the issue, but may also cause problems when a specific memory layout is expected by an application.
3. Fix the unit test by always requesting a memory layout with adequate alignment in texture_builder_init.[2]
Option 3. seems to be the most prudent, since it wouldn't cause problems on other architectures where the memory alignment doesn't matter.
On the other hand, it would hide the fact that inadequate memory alignments in user programs may lead to crashes when the target CPU doesn't support it.
I've included an untested patch for option 3.
[1] testsuite/gdk/mipmap.c https://salsa.debian.org/gnome-team/gtk4/-/blob/debian/latest/testsuite/gdk/mipmap.c?ref_type=heads#L234
[2] testsuite/gdk/gdktestutils.c:texture_builder_init https://salsa.debian.org/gnome-team/gtk4/-/blob/debian/latest/testsuite/gdk/gdktestutils.c?ref_type=heads#L656
[3] gdk/gdkmemorylayout.c:gdk_memory_layout_init https://salsa.debian.org/gnome-team/gtk4/-/blob/debian/latest/gdk/gdkmemorylayout.c#L39
[4] testsuite/gdk/gdktestutils.c:gdk_memory_layout_fudge https://salsa.debian.org/gnome-team/gtk4/-/blob/debian/latest/testsuite/gdk/gdktestutils.c?ref_type=heads#L635
-- System Information:
Debian Release: forky/sid
APT prefers unreleased
APT policy: (500, 'unreleased'), (500, 'unstable')
Architecture: sparc64
Kernel: Linux 6.16.12+deb14+1-sparc64 (UP)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE=en_US:en
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
-------------- next part --------------
--- gtk4/testsuite/gdk/gdktestutils.c 2025-10-16 22:15:43.620309363 +0200
+++ gdktestutils.c 2025-10-25 02:04:24.709349454 +0200
@@ -177,6 +177,89 @@
}
}
+gsize
+gdk_memory_format_get_alignment (GdkMemoryFormat format)
+{
+ switch (format)
+ {
+ case GDK_MEMORY_R8G8B8:
+ case GDK_MEMORY_B8G8R8:
+ case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+ case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+ case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
+ case GDK_MEMORY_A8B8G8R8_PREMULTIPLIED:
+ case GDK_MEMORY_B8G8R8A8:
+ case GDK_MEMORY_A8R8G8B8:
+ case GDK_MEMORY_R8G8B8A8:
+ case GDK_MEMORY_A8B8G8R8:
+ case GDK_MEMORY_B8G8R8X8:
+ case GDK_MEMORY_X8R8G8B8:
+ case GDK_MEMORY_R8G8B8X8:
+ case GDK_MEMORY_X8B8G8R8:
+ case GDK_MEMORY_G8:
+ case GDK_MEMORY_G8A8:
+ case GDK_MEMORY_G8A8_PREMULTIPLIED:
+ case GDK_MEMORY_A8:
+ case GDK_MEMORY_G8_B8R8_420:
+ case GDK_MEMORY_G8_R8B8_420:
+ case GDK_MEMORY_G8_B8R8_422:
+ case GDK_MEMORY_G8_R8B8_422:
+ case GDK_MEMORY_G8_B8R8_444:
+ case GDK_MEMORY_G8_R8B8_444:
+ case GDK_MEMORY_G8_B8_R8_410:
+ case GDK_MEMORY_G8_R8_B8_410:
+ case GDK_MEMORY_G8_B8_R8_411:
+ case GDK_MEMORY_G8_R8_B8_411:
+ case GDK_MEMORY_G8_B8_R8_420:
+ case GDK_MEMORY_G8_R8_B8_420:
+ case GDK_MEMORY_G8_B8_R8_422:
+ case GDK_MEMORY_G8_R8_B8_422:
+ case GDK_MEMORY_G8_B8_R8_444:
+ case GDK_MEMORY_G8_R8_B8_444:
+ case GDK_MEMORY_G8B8G8R8_422:
+ case GDK_MEMORY_G8R8G8B8_422:
+ case GDK_MEMORY_R8G8B8G8_422:
+ case GDK_MEMORY_B8G8R8G8_422:
+ return 1;
+
+ case GDK_MEMORY_R16G16B16:
+ case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+ case GDK_MEMORY_R16G16B16A16:
+ case GDK_MEMORY_G16:
+ case GDK_MEMORY_G16A16:
+ case GDK_MEMORY_G16A16_PREMULTIPLIED:
+ case GDK_MEMORY_A16:
+ case GDK_MEMORY_G10X6_B10X6R10X6_420:
+ case GDK_MEMORY_G12X4_B12X4R12X4_420:
+ case GDK_MEMORY_G16_B16R16_420:
+ case GDK_MEMORY_X6G10_X6B10_X6R10_420:
+ case GDK_MEMORY_X6G10_X6B10_X6R10_422:
+ case GDK_MEMORY_X6G10_X6B10_X6R10_444:
+ case GDK_MEMORY_X4G12_X4B12_X4R12_420:
+ case GDK_MEMORY_X4G12_X4B12_X4R12_422:
+ case GDK_MEMORY_X4G12_X4B12_X4R12_444:
+ case GDK_MEMORY_G16_B16_R16_420:
+ case GDK_MEMORY_G16_B16_R16_422:
+ case GDK_MEMORY_G16_B16_R16_444:
+ case GDK_MEMORY_R16G16B16_FLOAT:
+ case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+ case GDK_MEMORY_R16G16B16A16_FLOAT:
+ case GDK_MEMORY_A16_FLOAT:
+ return 2;
+
+ case GDK_MEMORY_R32G32B32_FLOAT:
+ case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+ case GDK_MEMORY_R32G32B32A32_FLOAT:
+ case GDK_MEMORY_A32_FLOAT:
+ return 4;
+
+ case GDK_MEMORY_N_FORMATS:
+ default:
+ g_assert_not_reached ();
+ return 1;
+ }
+}
+
void
gdk_memory_pixel_print (const guchar *data,
const GdkMemoryLayout *layout,
@@ -658,8 +741,11 @@
int width,
int height)
{
- gdk_memory_layout_init (&builder->layout, format, width, height, 1);
- gdk_memory_layout_fudge (&builder->layout, 1);
+ gsize align;
+
+ align = gdk_memory_format_get_alignment (format);
+ gdk_memory_layout_init (&builder->layout, format, width, height, align);
+ gdk_memory_layout_fudge (&builder->layout, align);
builder->pixels = g_malloc0 (builder->layout.size);
}
More information about the pkg-gnome-maintainers
mailing list