From ad2a739881f3772199a3a8ae42f8fc2c0588ff61 Mon Sep 17 00:00:00 2001 From: Jeroen Hofstee Date: Fri, 9 Jan 2026 17:06:28 +0100 Subject: [PATCH] src: fix pointer alignment The NgLibMemoryManager::ReallocImpl method 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. On Arm 32bits this resulted in unaligned accesses, since the NEON vst1.64 instruction was used with a not properly aligned addresses. A reproducer is available at [1]. Correct this by allocating the maximum of the the size of the size_t and the max alignment. [1] https://github.com/victronenergy/venus/issues/1559. --- src/node_mem-inl.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/node_mem-inl.h b/src/node_mem-inl.h index 70d28dd524be84..64f4704e62bb0c 100644 --- a/src/node_mem-inl.h +++ b/src/node_mem-inl.h @@ -8,6 +8,8 @@ namespace node { namespace mem { +static constexpr size_t kReserveSizeAndAlign = + std::max(sizeof(size_t), alignof(max_align_t)); template AllocatorStruct NgLibMemoryManager::MakeAllocator() { @@ -30,19 +32,18 @@ void* NgLibMemoryManager::ReallocImpl(void* ptr, char* original_ptr = nullptr; // We prepend each allocated buffer with a size_t containing the full - // size of the allocation. - if (size > 0) size += sizeof(size_t); + // size of the allocation, while keeping the returned pointer aligned. + if (size > 0) size += kReserveSizeAndAlign; if (ptr != nullptr) { // We are free()ing or re-allocating. - original_ptr = static_cast(ptr) - sizeof(size_t); + original_ptr = static_cast(ptr) - kReserveSizeAndAlign; previous_size = *reinterpret_cast(original_ptr); // This means we called StopTracking() on this pointer before. if (previous_size == 0) { // Fall back to the standard Realloc() function. char* ret = UncheckedRealloc(original_ptr, size); - if (ret != nullptr) - ret += sizeof(size_t); + if (ret != nullptr) ret += kReserveSizeAndAlign; return ret; } } @@ -62,7 +63,7 @@ void* NgLibMemoryManager::ReallocImpl(void* ptr, manager->env()->external_memory_accounter()->Update( manager->env()->isolate(), new_size); *reinterpret_cast(mem) = size; - mem += sizeof(size_t); + mem += kReserveSizeAndAlign; } else if (size == 0) { manager->DecreaseAllocatedSize(previous_size); manager->env()->external_memory_accounter()->Decrease( @@ -95,8 +96,8 @@ void* NgLibMemoryManager::CallocImpl(size_t nmemb, template void NgLibMemoryManager::StopTrackingMemory(void* ptr) { - size_t* original_ptr = reinterpret_cast( - static_cast(ptr) - sizeof(size_t)); + size_t* original_ptr = + reinterpret_cast(static_cast(ptr) - kReserveSizeAndAlign); Class* manager = static_cast(this); manager->DecreaseAllocatedSize(*original_ptr); manager->env()->external_memory_accounter()->Decrease(