[PATCH] expand: Avoid unaligned access through uint64_t pointer

Tiago de Paula <[email protected]> Fri, 13 Feb 2026 21:09:58 -0800
Newsgroups org.kernel.vger.dash
Message-ID <CAO_NRt6m0gYC4A-O19mebUAePSQ_X7gbuSyuxHevWE4xHnWMAg@mail.gmail.com>
Use memcpy to reduce alignment from 8 to 1. Unaligned access in this
case is undefined behavior and can lead to invalid machine code in
architectures with strict alignment requirements or after compiler
optimizations.

Fixes: c0c860df08c9 ("expand: Count multi-byte characters")
Signed-off-by: Tiago de Paula <[email protected]>
---
I was getting crashes when compiling with '-march=native -mtune=native -O3'.
Building with ASAN avoided the crashes, but I got these warnings instead:

    expand.c:964:13: runtime error: load of misaligned address
0x7ffe4892c997 for type 'uint64_t', which requires 8 byte alignment
    0x7ffe4892c997: note: pointer points here
    61 73 68 00 43  6f 6e 66 69 67 75 72 65  00 2d 64 65 00 2d 44 70
72 65 66 69 78 3d 2f 68  6f 6d 65
                ^
    expand.c:970:29: runtime error: store to misaligned address
0x558de50b48e3 for type 'uint64_t', which requires 8 byte alignment
    0x558de50b48e3: note: pointer points here
    00  6d 65 3d 00 8d 55 00 00  10 49 0b e5 8d 55 00 00  d8 48 0b e5
8d 55 00 00  00 00 00 00 00 00 00
                ^
    expand.c:1338:13: runtime error: load of misaligned address
0x7d49bf7e2889 for type 'uint64_t', which requires 8 byte alignment
    0x7d49bf7e2889: note: pointer points here
    7c 00 00  2f 62 69 6e 20 2f 75 73  72 2f 62 69 6e 20 2f 75  73 72
2f 6c 6f 63 61 6c  2f 62 69 6e 20
                ^

Which led me to connect the dots and make this fix. I was also able to
reproduce the crash with just '-march=x86-64-v2 -mtune=generic -O3 -g',
but not with -O2 or -march=x86-64 alone, so it might be triggered by
the interaction of two of more optimization flags. The patch does fix
the issue for me, though, so I didn't try to find the exact flags that
do that.

 src/expand.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/expand.c b/src/expand.c
index 8c8bf0e..72d11cb 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -961,13 +961,14 @@ static size_t memtodest(const char *p, size_t
len, int flags)
 	if (likely(!(flags & (expq >> 3 | expq >> 4 | expq >> 8) &
 		     (QUOTES_ESC | EXP_MBCHAR)))) {
 		while (len >= 8) {
-			uint64_t x = *(uint64_t *)(p + count);
+			uint64_t x;
+			memcpy(&x, p + count, sizeof(uint64_t));

 			if ((x | (x - 0x0101010101010101)) &
 			    0x8080808080808080)
 				break;

-			*(uint64_t *)(q + count) = x;
+			memcpy(q + count, &x, sizeof(uint64_t));

 			count += 8;
 			len -= 8;
@@ -1335,7 +1336,7 @@ ifsbreakup(char *string, int maxargs, struct
arglist *arglist)
 						unsigned char b[8];
 					} x;

-					x.qw = *(uint64_t *)p;
+					memcpy(&x.qw, p, sizeof(uint64_t));

 					if ((x.qw & 0x8080808080808080))
 						break;
-- 
2.53.0