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;
     }

Reply via email to