diff --git a/patches/node/.patches b/patches/node/.patches index ea57fbb74b3..90ab26d2ade 100644 --- a/patches/node/.patches +++ b/patches/node/.patches @@ -48,3 +48,4 @@ feat_add_oom_error_callback_in_node_isolatesettings.patch fix_-wnonnull_warning.patch refactor_attach_cppgc_heap_on_v8_isolate_creation.patch fix_ensure_traverseparent_bails_on_resource_path_exit.patch +zlib_fix_pointer_alignment.patch diff --git a/patches/node/zlib_fix_pointer_alignment.patch b/patches/node/zlib_fix_pointer_alignment.patch new file mode 100644 index 00000000000..47c51a49e62 --- /dev/null +++ b/patches/node/zlib_fix_pointer_alignment.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeroen Hofstee +Date: Tue, 1 Apr 2025 20:09:31 +0000 +Subject: zlib: fix pointer alignment + +The function AllocForBrotli prefixes the allocated memory with its +size, and returns a pointer to the region after it. This pointer can +however no longer be suitably aligned. Correct this by allocating +the maximum of the the size of the size_t and the max alignment. + +On Arm 32bits the size_t is 4 bytes long, but the alignment is 8 for +some NEON instructions. When Brotli is compiled with optimizations +enabled newer GCC versions will use the NEON instructions and trigger +a bus error killing node. + +see https://github.com/google/brotli/issues/1159 + +diff --git a/src/node_zlib.cc b/src/node_zlib.cc +index 90307cd4984ae5aa55386f2980ad9cd540322dfd..6f12b5034d1a98da50c064cf2cfdf12fc88137eb 100644 +--- a/src/node_zlib.cc ++++ b/src/node_zlib.cc +@@ -493,7 +493,8 @@ class CompressionStream : public AsyncWrap, public ThreadPoolWork { + } + + static void* AllocForBrotli(void* data, size_t size) { +- size += sizeof(size_t); ++ constexpr size_t offset = std::max(sizeof(size_t), alignof(max_align_t)); ++ size += offset; + CompressionStream* ctx = static_cast(data); + char* memory = UncheckedMalloc(size); + if (memory == nullptr) [[unlikely]] { +@@ -502,7 +503,7 @@ class CompressionStream : public AsyncWrap, public ThreadPoolWork { + *reinterpret_cast(memory) = size; + ctx->unreported_allocations_.fetch_add(size, + std::memory_order_relaxed); +- return memory + sizeof(size_t); ++ return memory + offset; + } + + static void FreeForZlib(void* data, void* pointer) { +@@ -510,7 +511,8 @@ class CompressionStream : public AsyncWrap, public ThreadPoolWork { + return; + } + CompressionStream* ctx = static_cast(data); +- char* real_pointer = static_cast(pointer) - sizeof(size_t); ++ constexpr size_t offset = std::max(sizeof(size_t), alignof(max_align_t)); ++ char* real_pointer = static_cast(pointer) - offset; + size_t real_size = *reinterpret_cast(real_pointer); + ctx->unreported_allocations_.fetch_sub(real_size, + std::memory_order_relaxed);