From 44db240bc193475d4712ffb5553288c011964d3d Mon Sep 17 00:00:00 2001 From: iceray-Li <108821718+iceray00@users.noreply.github.com> Date: Tue, 22 Sep 2026 04:11:43 +0000 Subject: [PATCH] Makefile: build the vendored Brotli without unaligned typed loads The fuzz targets are built by this Makefile, which compiles the Brotli decoder from the brotli submodule. Brotli's default build reads 16, 32 and 64-bit words by casting a byte pointer to the target type and dereferencing it. The compressed input is byte addressed and advances by arbitrary amounts, so those pointers are frequently misaligned, and the dereference is undefined behavior on both the alignment and the strict aliasing count. The upstream harness src/convert_woff2ttf_fuzzer.cc reports it: c/dec/../common/platform.h:214:10: runtime error: load of misaligned address 0x630000010469 for type 'const uint32_t' (aka 'const unsigned int'), which requires 4 byte alignment #0 BrotliUnalignedRead32 brotli/c/common/platform.h:214:10 #1 BrotliFillBitWindow brotli/c/dec/bit_reader.h:130:30 #2 BrotliFillBitWindow16 brotli/c/dec/bit_reader.h:159:3 #3 ReadSymbolCodeLengths brotli/c/dec/decode.c:607:5 #4 ReadHuffmanCode brotli/c/dec/decode.c:826:41 ... #7 woff2::Woff2Uncompress src/woff2_dec.cc:801:32 #8 woff2::ConvertWOFF2ToTTF src/woff2_dec.cc:1381:7 woff2 hands Brotli the raw compressed bytes of the WOFF2 stream, so the misalignment cannot be avoided from this side. It is not specific to malformed fonts either; a handful of ordinary WOFF2 fonts trips the same read on the first file. Brotli uses memcpy based loads when BROTLI_BUILD_PORTABLE is defined, and its own CMake defines it for undefined behavior sanitizer builds. Pass it when building the dependency here, so that `make`, which produces the fuzz targets, no longer depends on undefined behavior. Refreshing the brotli submodule to a release that no longer has the casts would also work, but not by itself: Brotli removed its Makefile build in July 2023 and this Makefile still drives that one, so moving woff2 onto Brotli's CMake build has to happen first (#144, #162). Decoding is unchanged: both builds decode real fonts to byte identical output, and compilers still emit a single load on targets that support unaligned access. --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fbb945c..f607125 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,10 @@ CXX ?= g++ CANONICAL_PREFIXES ?= -no-canonical-prefixes NOISY_LOGGING ?= -DFONT_COMPRESSION_BIN COMMON_FLAGS = -fno-omit-frame-pointer $(CANONICAL_PREFIXES) $(NOISY_LOGGING) -D __STDC_FORMAT_MACROS +# Brotli reads words by casting a byte pointer to the target type unless it is +# built in its portable mode. Those pointers are not aligned, so the casts are +# undefined behavior; use the memcpy based loads instead. +BROTLI_CPPFLAGS ?= -DBROTLI_BUILD_PORTABLE ARFLAGS = crf @@ -56,7 +60,7 @@ $(EXECUTABLES) : $(EXE_OBJS) deps $(CXX) $(LFLAGS) $(OBJS) $(COMMONOBJ) $(ENCOBJ) $(DECOBJ) $(SRCDIR)/$@.o -o $@ deps : - $(MAKE) -C $(BROTLI) lib + $(MAKE) -C $(BROTLI) lib CPPFLAGS="$(BROTLI_CPPFLAGS)" clean : rm -f $(OBJS) $(EXE_OBJS) $(EXECUTABLES)