Repository: electron/electron
Pull request: fix: zlib pointer alignment

#### Description of Change

Refs https://github.com/google/brotli/issues/1159
Refs https://github.com/nodejs/node/pull/57727

Fixes a possible issue with brotli and Node.js on some arm32 devices:

> 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.

#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: Fixes a possible crash using Node.js on some arm32 devices.

Changed files:
filename: patches/node/.patches
patch: @@ -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

filename: patches/node/zlib_fix_pointer_alignment.patch
patch: @@ -0,0 +1,50 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jeroen Hofstee <jhofstee@victronenergy.com>
+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<CompressionStream*>(data);
+     char* memory = UncheckedMalloc(size);
+     if (memory == nullptr) [[unlikely]] {
+@@ -502,7 +503,7 @@ class CompressionStream : public AsyncWrap, public ThreadPoolWork {
+     *reinterpret_cast<size_t*>(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<CompressionStream*>(data);
+-    char* real_pointer = static_cast<char*>(pointer) - sizeof(size_t);
++    constexpr size_t offset = std::max(sizeof(size_t), alignof(max_align_t));
++    char* real_pointer = static_cast<char*>(pointer) - offset;
+     size_t real_size = *reinterpret_cast<size_t*>(real_pointer);
+     ctx->unreported_allocations_.fetch_sub(real_size,
+                                            std::memory_order_relaxed);