[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