[compiler-rt] db63c56 - [ASan][AIX] Intercept __linux_vec_malloc/__linux_vec_calloc/__linux_realloc (#209359)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 07:07:58 PDT 2026


Author: Midhunesh
Date: 2026-07-14T19:37:53+05:30
New Revision: db63c56a4f985426a0c44de4da215eb06cd5a278

URL: https://github.com/llvm/llvm-project/commit/db63c56a4f985426a0c44de4da215eb06cd5a278
DIFF: https://github.com/llvm/llvm-project/commit/db63c56a4f985426a0c44de4da215eb06cd5a278.diff

LOG: [ASan][AIX] Intercept __linux_vec_malloc/__linux_vec_calloc/__linux_realloc (#209359)

On AIX PASE, when `__VEC__` and `_ALL_SOURCE` are defined, the XL
compiler frontend lowers calls to vec_malloc/vec_calloc/realloc to
internal symbols named `__linux_vec_malloc`, `__linux_vec_calloc`, and
`__linux_realloc` instead of the standard
`vec_malloc`/`vec_calloc`/`realloc` names. These symbols were not
intercepted, so allocations made through them bypassed ASan entirely, no
redzone poisoning, no use-after-free or overflow detection.
This adds interceptors for `__linux_vec_malloc`, `__linux_vec_calloc`,
and `__linux_realloc`, following the same pattern as the existing
`vec_malloc`/`vec_calloc` interceptors (#175584): `__linux_vec_malloc`
and `__linux_vec_calloc` route through
`asan_vec_malloc`/`asan_vec_calloc` (16-byte aligned), and
`__linux_realloc` routes through the existing `asan_realloc`.

---------

Co-authored-by: Midhunesh <midhuensh.p at ibm.com>

Added: 
    

Modified: 
    compiler-rt/lib/asan/AIX/asan.link_with_main_exec.txt
    compiler-rt/lib/asan/asan_malloc_linux.cpp
    compiler-rt/test/asan/TestCases/AIX/vec_malloc_calloc.cpp

Removed: 
    


################################################################################
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..0e02267803fbd 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___linux_vec_malloc
+__linux_vec_malloc
+__interceptor___linux_vec_calloc
+__linux_vec_calloc
+__interceptor___linux_realloc
+__linux_realloc

diff  --git a/compiler-rt/lib/asan/asan_malloc_linux.cpp b/compiler-rt/lib/asan/asan_malloc_linux.cpp
index 21c6467fe1753..a0898bb98da00 100644
--- a/compiler-rt/lib/asan/asan_malloc_linux.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_linux.cpp
@@ -92,6 +92,15 @@ INTERCEPTOR(void*, vec_malloc, uptr size) {
   return asan_vec_malloc(size, &stack);
 }
 
+// __linux_vec_malloc is the XL compiler internal symbol emitted instead of
+// vec_malloc.
+INTERCEPTOR(void*, __linux_vec_malloc, uptr size) {
+  if (DlsymAlloc::Use())
+    return DlsymAlloc::Allocate(size, 16);
+  GET_STACK_TRACE_MALLOC;
+  return asan_vec_malloc(size, &stack);
+}
+
 // Unlike calloc, vec_calloc must return memory aligned to 16 bytes.
 INTERCEPTOR(void*, vec_calloc, uptr nmemb, uptr size) {
   if (DlsymAlloc::Use())
@@ -99,6 +108,15 @@ INTERCEPTOR(void*, vec_calloc, uptr nmemb, uptr size) {
   GET_STACK_TRACE_MALLOC;
   return asan_vec_calloc(nmemb, size, &stack);
 }
+
+// __linux_vec_calloc is the XL compiler internal symbol emitted instead of
+// vec_calloc.
+INTERCEPTOR(void*, __linux_vec_calloc, uptr nmemb, uptr size) {
+  if (DlsymAlloc::Use())
+    return DlsymAlloc::Callocate(nmemb, size, 16);
+  GET_STACK_TRACE_MALLOC;
+  return asan_vec_calloc(nmemb, size, &stack);
+}
 #  endif
 
 // TODO: Fix malloc/calloc interceptors to return 16-byte alignment with AIX on
@@ -127,6 +145,17 @@ INTERCEPTOR(void*, realloc, void* ptr, uptr size) {
   return asan_realloc(ptr, size, &stack);
 }
 
+#  if SANITIZER_AIX
+// __linux_realloc is the XL compiler internal symbol emitted instead of
+// realloc.
+INTERCEPTOR(void*, __linux_realloc, void* ptr, uptr size) {
+  if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
+    return DlsymAlloc::Realloc(ptr, size, kWordSize);
+  GET_STACK_TRACE_MALLOC;
+  return asan_realloc(ptr, size, &stack);
+}
+#  endif
+
 #  if SANITIZER_INTERCEPT_REALLOCARRAY
 INTERCEPTOR(void*, reallocarray, void* ptr, uptr nmemb, uptr size) {
   AsanInitFromRtl();

diff  --git a/compiler-rt/test/asan/TestCases/AIX/vec_malloc_calloc.cpp b/compiler-rt/test/asan/TestCases/AIX/vec_malloc_calloc.cpp
index ea59bdd58d1e8..91411450edc1b 100644
--- a/compiler-rt/test/asan/TestCases/AIX/vec_malloc_calloc.cpp
+++ b/compiler-rt/test/asan/TestCases/AIX/vec_malloc_calloc.cpp
@@ -1,12 +1,23 @@
-// Verify vec_malloc and vec_calloc interceptors
+// Verify vec_malloc and vec_calloc interceptors, along with their
+// XL-compiler-emitted counterparts __linux_vec_malloc, __linux_vec_calloc,
+// and __linux_realloc.
 
 // 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_malloc        2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-VEC-MALLOC
+// RUN: not %run %t linux_vec_malloc  2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-LINUX-VEC-MALLOC
+// RUN: not %run %t vec_calloc        2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-VEC-CALLOC
+// RUN: not %run %t linux_vec_calloc  2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-LINUX-VEC-CALLOC
+// RUN: not %run %t linux_realloc     2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-LINUX-REALLOC
 
 #include <stdlib.h>
 #include <string.h>
 
+extern "C" {
+void *__linux_vec_malloc(unsigned long size);
+void *__linux_vec_calloc(unsigned long nmemb, unsigned long size);
+void *__linux_realloc(void *ptr, unsigned long size);
+}
+
 int main(int argc, char **argv) {
   if (argc != 2)
     return 1;
@@ -14,17 +25,32 @@ int main(int argc, char **argv) {
   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], "linux_vec_malloc") == 0)
+    p = (char *)__linux_vec_malloc(10);
   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
+  else if (strcmp(argv[1], "linux_vec_calloc") == 0)
+    p = (char *)__linux_vec_calloc(10, 1);
+  else if (strcmp(argv[1], "linux_realloc") == 0) {
+    char *orig = (char *)__linux_vec_malloc(5);
+    p = (char *)__linux_realloc(orig, 10);
+  } else
     return 1;
 
+  // Assertions common to every allocator under test above.
+  // CHECK: {{READ of size 1 at 0x.* thread T0}}
+  // CHECK: {{0x.* is located 0 bytes after 10-byte region}}
+  // CHECK: {{allocated by thread T0 here:}}
+  //
+  // The allocation frame (not just some caller further up the backtrace)
+  // must be the specific symbol under test, otherwise this only proves that
+  // the real libc symbol forwarded to some other, already-intercepted
+  // function.
+  // CHECK-VEC-MALLOC-NEXT: {{#0 .* in .vec_malloc}}
+  // CHECK-LINUX-VEC-MALLOC-NEXT: {{#0 .* in .*__linux_vec_malloc}}
+  // CHECK-VEC-CALLOC-NEXT: {{#0 .* in .vec_calloc}}
+  // CHECK-LINUX-VEC-CALLOC-NEXT: {{#0 .* in .*__linux_vec_calloc}}
+  // CHECK-LINUX-REALLOC-NEXT: {{#0 .* in .*__linux_realloc}}
   char x = p[10];
   free(p);
 


        


More information about the llvm-commits mailing list