Source: zopfli Version: 1.0.3-3 Severity: important User: [email protected] Usertags: sparc64 X-Debbugs-Cc: [email protected]
Hi, there are some instances of unaligned access in zopfli that trigger Bus error crashes on sparc64 when running the testsuite of python-zopfli on sparc64 [1]. The upstream of python-zopfli just fixed [2] the issue after I reported it [3]. I'm attaching the patch, please considers cherry-picking it. Thanks, Adrian > [1] > https://buildd.debian.org/status/fetch.php?pkg=python-zopfli&arch=sparc64&ver=0.4.0-1&stamp=1762664749&raw=0 > [2] > https://github.com/fonttools/py-zopfli/commit/f87d464d1df5907d0035f559278421b125236fc5 > [3] https://github.com/fonttools/py-zopfli/issues/28 -- .''`. John Paul Adrian Glaubitz : :' : Debian Developer `. `' Physicist `- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
>From cd7f13b12a2c1a50f94ffe9ca5909854bdef8d93 Mon Sep 17 00:00:00 2001 From: Cosimo Lupo <[email protected]> Date: Fri, 13 Feb 2026 11:57:17 +0000 Subject: [PATCH] Fix SIGBUS on strict-alignment architectures (SPARC, MIPS) GetMatch() casts unsigned char* pointers to size_t* and unsigned int* and dereferences them for word-at-a-time comparison. These pointers can be at any byte offset, so the casts produce unaligned accesses which cause SIGBUS on strict-alignment architectures (SPARC, MIPS64, etc.) and are undefined behavior per the C standard. Replace the direct pointer casts with memcpy into properly aligned local variables. Modern compilers optimize memcpy of a known small size into a single load instruction on architectures that support unaligned access (x86), so there is no performance regression. Fixes google/zopfli#22 (open since 2013). Also fixes fonttools/py-zopfli#28. --- src/zopfli/lz77.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/zopfli/lz77.c b/src/zopfli/lz77.c index 9df899dd..52a2bed1 100644 --- a/src/zopfli/lz77.c +++ b/src/zopfli/lz77.c @@ -24,6 +24,7 @@ Author: [email protected] (Jyrki Alakuijala) #include <assert.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> void ZopfliInitLZ77Store(const unsigned char* data, ZopfliLZ77Store* store) { store->size = 0; @@ -300,15 +301,25 @@ static const unsigned char* GetMatch(const unsigned char* scan, const unsigned char* safe_end) { if (sizeof(size_t) == 8) { - /* 8 checks at once per array bounds check (size_t is 64-bit). */ - while (scan < safe_end && *((size_t*)scan) == *((size_t*)match)) { + /* 8 checks at once per array bounds check (size_t is 64-bit). + Use memcpy to avoid unaligned access (causes SIGBUS on strict-alignment + architectures like SPARC and MIPS). The compiler will optimize memcpy of + a known size into a single load where the architecture supports it. */ + size_t sv, mv; + while (scan < safe_end) { + memcpy(&sv, scan, sizeof(sv)); + memcpy(&mv, match, sizeof(mv)); + if (sv != mv) break; scan += 8; match += 8; } } else if (sizeof(unsigned int) == 4) { /* 4 checks at once per array bounds check (unsigned int is 32-bit). */ - while (scan < safe_end - && *((unsigned int*)scan) == *((unsigned int*)match)) { + unsigned int sv, mv; + while (scan < safe_end) { + memcpy(&sv, scan, sizeof(sv)); + memcpy(&mv, match, sizeof(mv)); + if (sv != mv) break; scan += 4; match += 4; }

