[compiler-rt] Fix 16-byte alignment for vec allocators on AIX (PR #184967)

via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 6 00:25:57 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Midhunesh (midhuncodes7)

<details>
<summary>Changes</summary>

On AIX PASE, malloc/calloc/realloc map to their vec_* equivalents by default, all of which require 16-byte aligned memory. ASan's interceptors were returning only 8-byte aligned pointers, and realloc was silently downgrading the alignment.

This patch fixes all affected interceptors (__linux_vec_malloc, __linux_vec_calloc, __linux_realloc, malloc, calloc, realloc) to return 16-byte aligned memory on AIX, adds the missing vec_realloc interceptor.

vec_malloc and vec_calloc are implemented [here](https://github.com/llvm/llvm-project/pull/175584).

---
Full diff: https://github.com/llvm/llvm-project/pull/184967.diff


7 Files Affected:

- (modified) compiler-rt/lib/asan/AIX/asan.link_with_main_exec.txt (+6) 
- (modified) compiler-rt/lib/asan/asan_allocator.cpp (+12-2) 
- (modified) compiler-rt/lib/asan/asan_allocator.h (+1) 
- (modified) compiler-rt/lib/asan/asan_malloc_linux.cpp (+46-8) 
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h (+3-3) 
- (added) compiler-rt/test/asan/TestCases/AIX/vec_alloc_align.cpp (+108) 
- (removed) compiler-rt/test/asan/TestCases/AIX/vec_malloc_calloc.cpp (-32) 


``````````diff
diff --git a/compiler-rt/lib/asan/AIX/asan.link_with_main_exec.txt b/compiler-rt/lib/asan/AIX/asan.link_with_main_exec.txt
index 5efc48c262369..4bc85e3e50256 100644
--- a/compiler-rt/lib/asan/AIX/asan.link_with_main_exec.txt
+++ b/compiler-rt/lib/asan/AIX/asan.link_with_main_exec.txt
@@ -113,3 +113,9 @@ __asan_poison_stack_memory
 __asan_unpoison_stack_memory
 __asan_option_detect_stack_use_after_return
 __asan_shadow_memory_dynamic_address
+__interceptor_vec_calloc
+__interceptor_vec_malloc
+__interceptor_vec_realloc
+vec_calloc
+vec_malloc
+vec_realloc
diff --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp
index 59aeec6a6ae66..cce89adb1539e 100644
--- a/compiler-rt/lib/asan/asan_allocator.cpp
+++ b/compiler-rt/lib/asan/asan_allocator.cpp
@@ -783,8 +783,12 @@ struct Allocator {
     AsanStats &thread_stats = GetCurrentThreadStats();
     thread_stats.reallocs++;
     thread_stats.realloced += new_size;
-
-    void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true);
+    
+    // Preserve the original allocation's alignment
+    uptr orig_align = ComputeUserAlignment(m->user_requested_alignment_log);
+    if (orig_align < 8)
+      orig_align = 8;
+    void *new_ptr = Allocate(new_size, orig_align, stack, FROM_MALLOC, true);
     if (new_ptr) {
       u8 chunk_state = atomic_load(&m->chunk_state, memory_order_acquire);
       if (chunk_state != CHUNK_ALLOCATED)
@@ -1059,6 +1063,12 @@ void* asan_vec_malloc(uptr size, BufferedStackTrace* stack) {
 void* asan_vec_calloc(uptr nmemb, uptr size, BufferedStackTrace* stack) {
   return SetErrnoOnNull(instance.Calloc(nmemb, size, stack, 16));
 }
+
+void* asan_vec_realloc(void* p, uptr size, BufferedStackTrace* stack) {
+  if (!p)
+    return SetErrnoOnNull(instance.Allocate(size, 16, stack, FROM_MALLOC, true));
+  return asan_realloc(p, size, stack);
+}
 #endif
 
 void *asan_reallocarray(void *p, uptr nmemb, uptr size,
diff --git a/compiler-rt/lib/asan/asan_allocator.h b/compiler-rt/lib/asan/asan_allocator.h
index 8521e8d068db1..63f7ee6730e55 100644
--- a/compiler-rt/lib/asan/asan_allocator.h
+++ b/compiler-rt/lib/asan/asan_allocator.h
@@ -283,6 +283,7 @@ void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
 #if SANITIZER_AIX
 void* asan_vec_malloc(uptr size, BufferedStackTrace* stack);
 void* asan_vec_calloc(uptr nmemb, uptr size, BufferedStackTrace* stack);
+void* asan_vec_realloc(void* p, uptr size, BufferedStackTrace* stack);
 #endif
 void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
 void *asan_reallocarray(void *p, uptr nmemb, uptr size,
diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cpp b/compiler-rt/lib/asan/asan_malloc_linux.cpp
index a1b10a5fb8558..8c5b19dd3b9da 100644
--- a/compiler-rt/lib/asan/asan_malloc_linux.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_linux.cpp
@@ -53,6 +53,29 @@ INTERCEPTOR(void, free, void *ptr) {
 }
 
 #if SANITIZER_INTERCEPT_CFREE
+INTERCEPTOR(void*, __linux_vec_malloc, uptr size) {
+   if (DlsymAlloc::Use())
+     return DlsymAlloc::Allocate(size, 16);
+   AsanInitFromRtl();
+   GET_STACK_TRACE_MALLOC;
+   return asan_vec_malloc(size, &stack);
+ }
+
+INTERCEPTOR(void*, __linux_vec_calloc, uptr nmemb, uptr size) {
+  if (DlsymAlloc::Use())
+    return DlsymAlloc::Callocate(nmemb, size, 16);
+  AsanInitFromRtl();
+  GET_STACK_TRACE_MALLOC;
+  return asan_vec_calloc(nmemb, size, &stack);
+}
+
+INTERCEPTOR(void*, __linux_realloc, void* ptr, uptr size) {
+  if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
+    return DlsymAlloc::Realloc(ptr, size, 16);
+  GET_STACK_TRACE_MALLOC;
+  return asan_vec_realloc(ptr, size, &stack);
+}
+
 INTERCEPTOR(void, cfree, void *ptr) {
   if (DlsymAlloc::PointerIsMine(ptr))
     return DlsymAlloc::Free(ptr);
@@ -77,32 +100,47 @@ INTERCEPTOR(void*, vec_calloc, uptr nmemb, uptr size) {
   GET_STACK_TRACE_MALLOC;
   return asan_vec_calloc(nmemb, size, &stack);
 }
+
+// Unlike realloc, vec_realloc must return memory aligned to 16 bytes.
+INTERCEPTOR(void*, vec_realloc, void* ptr, uptr size) {
+  if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
+    return DlsymAlloc::Realloc(ptr, size, 16);
+  GET_STACK_TRACE_MALLOC;
+  return asan_vec_realloc(ptr, size, &stack);
+}
 #  endif
 
-// TODO: Fix malloc/calloc interceptors to return 16-byte alignment with AIX on
-// PASE.
 INTERCEPTOR(void*, malloc, uptr size) {
   if (DlsymAlloc::Use())
-    return DlsymAlloc::Allocate(size);
+    return DlsymAlloc::Allocate(size, SANITIZER_AIX ? 16 : kWordSize);
   GET_STACK_TRACE_MALLOC;
+#if SANITIZER_AIX
+  return asan_vec_malloc(size, &stack);
+#else
   return asan_malloc(size, &stack);
+#endif
 }
 
 INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
   if (DlsymAlloc::Use())
-    return DlsymAlloc::Callocate(nmemb, size);
+    return DlsymAlloc::Callocate(nmemb, size, SANITIZER_AIX ? 16 : kWordSize);
   GET_STACK_TRACE_MALLOC;
+#if SANITIZER_AIX
+  return asan_vec_calloc(nmemb, size, &stack);
+#else
   return asan_calloc(nmemb, size, &stack);
+#endif
 }
 
-// TODO: AIX needs a method to ensure 16-byte alignment if the incoming
-// pointer was allocated with a 16-byte alignment requirement (or perhaps
-// merely if it happens to have 16-byte alignment).
 INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
   if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
-    return DlsymAlloc::Realloc(ptr, size);
+    return DlsymAlloc::Realloc(ptr, size, SANITIZER_AIX ? 16 : kWordSize);
   GET_STACK_TRACE_MALLOC;
+#if SANITIZER_AIX
+  return asan_vec_realloc(ptr, size, &stack);
+#else
   return asan_realloc(ptr, size, &stack);
+#endif
 }
 
 #if SANITIZER_INTERCEPT_REALLOCARRAY
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h
index 35445b9aece50..f2d0141425717 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator_dlsym.h
@@ -53,9 +53,9 @@ struct DlSymAllocator {
     InternalFree(ptr);
   }
 
-  static void *Realloc(void *ptr, uptr new_size) {
+  static void *Realloc(void *ptr, uptr new_size, uptr align = kWordSize){
     if (!ptr)
-      return Allocate(new_size);
+      return Allocate(new_size, align);
     CHECK(internal_allocator()->FromPrimary(ptr));
     if (!new_size) {
       Free(ptr);
@@ -63,7 +63,7 @@ struct DlSymAllocator {
     }
     uptr size = GetSize(ptr);
     uptr memcpy_size = Min(new_size, size);
-    void *new_ptr = Allocate(new_size);
+    void *new_ptr = Allocate(new_size, align);
     if (new_ptr)
       internal_memcpy(new_ptr, ptr, memcpy_size);
     Free(ptr);
diff --git a/compiler-rt/test/asan/TestCases/AIX/vec_alloc_align.cpp b/compiler-rt/test/asan/TestCases/AIX/vec_alloc_align.cpp
new file mode 100644
index 0000000000000..37602da0871d7
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/AIX/vec_alloc_align.cpp
@@ -0,0 +1,108 @@
+// Verify vec_malloc, vec_calloc and vec_realloc interceptors, and that all
+// vec/plain allocators return 16-byte aligned memory on AIX.
+
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t vec_malloc  2>&1 | FileCheck %s --check-prefix=CHECK-MALLOC
+// RUN: not %run %t vec_calloc  2>&1 | FileCheck %s --check-prefix=CHECK-CALLOC
+// RUN: not %run %t vec_realloc 2>&1 | FileCheck %s --check-prefix=CHECK-REALLOC
+// RUN: %run %t align           2>&1 | FileCheck %s --check-prefix=CHECK-ALIGN
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Helper used by the "align" sub-test: prints OK/FAIL to stderr.
+static void check_align(const char *label, void *ptr) {
+  if (((size_t)ptr & 15) != 0) {
+    fprintf(stderr, "FAIL: %s ptr %p not 16-byte aligned\n", label, ptr);
+    exit(1);
+  }
+  fprintf(stderr, "OK: %s\n", label);
+}
+
+int main(int argc, char **argv) {
+  if (argc != 2)
+    return 1;
+
+  // --- overflow detection (existing) ---
+
+  char *p;
+  if (strcmp(argv[1], "vec_malloc") == 0)
+    p = (char *)vec_malloc(10);
+  // CHECK-MALLOC: {{READ of size 1 at 0x.* thread T0}}
+  // CHECK-MALLOC: {{0x.* is located 0 bytes after 10-byte region}}
+  // CHECK-MALLOC: {{0x.* in .vec_malloc}}
+  else if (strcmp(argv[1], "vec_calloc") == 0)
+    p = (char *)vec_calloc(10, 1);
+  // CHECK-CALLOC: {{READ of size 1 at 0x.* thread T0}}
+  // CHECK-CALLOC: {{0x.* is located 0 bytes after 10-byte region}}
+  // CHECK-CALLOC: {{0x.* in .vec_calloc}}
+  else if (strcmp(argv[1], "vec_realloc") == 0)
+    p = (char *)vec_realloc(NULL, 10);
+  // CHECK-REALLOC: {{READ of size 1 at 0x.* thread T0}}
+  // CHECK-REALLOC: {{0x.* is located 0 bytes after 10-byte region}}
+  // On AIX 32-bit vec_realloc resolves to the realloc symbol; match both.
+  // CHECK-REALLOC: {{0x.* in .*realloc}}
+
+  // --- 16-byte alignment checks ---
+
+  else if (strcmp(argv[1], "align") == 0) {
+    void *vm = vec_malloc(32);
+    check_align("vec_malloc", vm);
+    // CHECK-ALIGN: OK: vec_malloc
+
+    void *vc = vec_calloc(1, 32);
+    check_align("vec_calloc", vc);
+    // CHECK-ALIGN: OK: vec_calloc
+
+    void *vr_null = vec_realloc(NULL, 32);
+    check_align("vec_realloc(NULL)", vr_null);
+    // CHECK-ALIGN: OK: vec_realloc(NULL)
+
+    void *vr_vm = vec_realloc(vm, 64);
+    check_align("vec_realloc(vec_malloc_ptr)", vr_vm);
+    // CHECK-ALIGN: OK: vec_realloc(vec_malloc_ptr)
+
+    void *vr_vc = vec_realloc(vc, 64);
+    check_align("vec_realloc(vec_calloc_ptr)", vr_vc);
+    // CHECK-ALIGN: OK: vec_realloc(vec_calloc_ptr)
+
+    void *m = malloc(32);
+    check_align("malloc", m);
+    // CHECK-ALIGN: OK: malloc
+
+    void *c = calloc(1, 32);
+    check_align("calloc", c);
+    // CHECK-ALIGN: OK: calloc
+
+    void *re_null = realloc(NULL, 32);
+    check_align("realloc(NULL)", re_null);
+    // CHECK-ALIGN: OK: realloc(NULL)
+
+    void *re_m = realloc(m, 64);
+    check_align("realloc(malloc_ptr)", re_m);
+    // CHECK-ALIGN: OK: realloc(malloc_ptr)
+
+    void *vm2 = vec_malloc(32);
+    void *re_vm = realloc(vm2, 64);
+    check_align("realloc(vec_malloc_ptr)", re_vm);
+    // CHECK-ALIGN: OK: realloc(vec_malloc_ptr)
+
+    free(vr_null);
+    free(vr_vm);
+    free(vr_vc);
+    free(c);
+    free(re_null);
+    free(re_m);
+    free(re_vm);
+    return 0;
+  } else {
+    return 1;
+  }
+
+  char x = p[10];
+  free(p);
+
+  return x;
+}
\ No newline at end of file
diff --git a/compiler-rt/test/asan/TestCases/AIX/vec_malloc_calloc.cpp b/compiler-rt/test/asan/TestCases/AIX/vec_malloc_calloc.cpp
deleted file mode 100644
index ea59bdd58d1e8..0000000000000
--- a/compiler-rt/test/asan/TestCases/AIX/vec_malloc_calloc.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-// Verify vec_malloc and vec_calloc interceptors
-
-// RUN: %clangxx_asan -O0 %s -o %t
-// RUN: not %run %t vec_malloc 2>&1 | FileCheck %s --check-prefix=CHECK-MALLOC
-// RUN: not %run %t vec_calloc 2>&1 | FileCheck %s --check-prefix=CHECK-CALLOC
-
-#include <stdlib.h>
-#include <string.h>
-
-int main(int argc, char **argv) {
-  if (argc != 2)
-    return 1;
-
-  char *p;
-  if (strcmp(argv[1], "vec_malloc") == 0)
-    p = (char *)vec_malloc(10);
-  // CHECK-MALLOC: {{READ of size 1 at 0x.* thread T0}}
-  // CHECK-MALLOC: {{0x.* is located 0 bytes after 10-byte region}}
-  // CHECK-MALLOC: {{0x.* in .vec_malloc}}
-  else if (strcmp(argv[1], "vec_calloc") == 0)
-    p = (char *)vec_calloc(10, 1);
-  // CHECK-CALLOC: {{READ of size 1 at 0x.* thread T0}}
-  // CHECK-CALLOC: {{0x.* is located 0 bytes after 10-byte region}}
-  // CHECK-CALLOC: {{0x.* in .vec_calloc}}
-  else
-    return 1;
-
-  char x = p[10];
-  free(p);
-
-  return x;
-}

``````````

</details>


https://github.com/llvm/llvm-project/pull/184967


More information about the llvm-commits mailing list