[compiler-rt] 5ec3191 - [asan] Adjust interception compatibility for AIX (#131870)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 2 14:31:31 PST 2026


Author: Jake Egan
Date: 2026-01-02T17:31:26-05:00
New Revision: 5ec319119f52aa7a8ab384bf58d341e7b69cdd59

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

LOG: [asan] Adjust interception compatibility for AIX (#131870)

Adjust asan interceptor compatbility for AIX. AIX uses dlsym to retrieve
addresses of exported functions. However, some functions in libc.a, such
as memcpy, are not exported, so we currently have a limitation in
retrieving these addresses.

Issue: https://github.com/llvm/llvm-project/issues/138916

Added: 
    

Modified: 
    compiler-rt/lib/asan/asan_interceptors.cpp
    compiler-rt/lib/asan/asan_interceptors.h
    compiler-rt/lib/asan/asan_malloc_linux.cpp
    compiler-rt/lib/interception/interception_aix.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp
    compiler-rt/lib/sanitizer_common/sanitizer_libc.h
    compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp
index dab05e2e8d755..02f0ffde72042 100644
--- a/compiler-rt/lib/asan/asan_interceptors.cpp
+++ b/compiler-rt/lib/asan/asan_interceptors.cpp
@@ -282,7 +282,12 @@ INTERCEPTOR(int, pthread_create, void* thread, void* attr,
 #    endif
     asanThreadArgRetval().Create(detached, {start_routine, arg}, [&]() -> uptr {
       result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
+// AIX pthread_t is unsigned int.
+#    if SANITIZER_AIX
+      return result ? 0 : *(unsigned*)(thread);
+#    else
       return result ? 0 : *(uptr*)(thread);
+#    endif
     });
   }
   if (result != 0) {
@@ -439,10 +444,12 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t* oucp, struct ucontext_t* ucp) {
 #    define siglongjmp __siglongjmp14
 #  endif
 
+#  if ASAN_INTERCEPT_LONGJMP
 INTERCEPTOR(void, longjmp, void* env, int val) {
   __asan_handle_no_return();
   REAL(longjmp)(env, val);
 }
+#  endif
 
 #  if ASAN_INTERCEPT__LONGJMP
 INTERCEPTOR(void, _longjmp, void* env, int val) {
@@ -867,7 +874,9 @@ void InitializeAsanInterceptors() {
 #  endif
 
   // Intercept jump-related functions.
+#  if ASAN_INTERCEPT_LONGJMP
   ASAN_INTERCEPT_FUNC(longjmp);
+#  endif
 
 #  if ASAN_INTERCEPT_SWAPCONTEXT
   ASAN_INTERCEPT_FUNC(swapcontext);

diff  --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h
index 7081e8bbb2af0..2d806b7df8ffb 100644
--- a/compiler-rt/lib/asan/asan_interceptors.h
+++ b/compiler-rt/lib/asan/asan_interceptors.h
@@ -31,10 +31,26 @@ void InitializePlatformInterceptors();
 // really defined to replace libc functions.
 #if !SANITIZER_FUCHSIA
 
+// Sanitizer on AIX is currently unable to retrieve the address
+// of the real longjump (or an alternative thereto).
+// TODO: Consider intercepting longjmpx on AIX.
+#  if !SANITIZER_AIX
+#    define ASAN_INTERCEPT_LONGJMP 1
+#  else
+#    define ASAN_INTERCEPT_LONGJMP 0
+#  endif
+
 // Use macro to describe if specific function should be
 // intercepted on a given platform.
 #  if !SANITIZER_WINDOWS
-#    define ASAN_INTERCEPT__LONGJMP 1
+   // Sanitizer on AIX is currently unable to retrieve the address
+   // of the real _longjump (or an alternative thereto).
+   // TODO: Consider intercepting _longjmpx on AIX.
+#    if !SANITIZER_AIX
+#      define ASAN_INTERCEPT__LONGJMP 1
+#    else
+#      define ASAN_INTERCEPT__LONGJMP 0
+#    endif
 #    define ASAN_INTERCEPT_INDEX 1
 #    define ASAN_INTERCEPT_PTHREAD_CREATE 1
 #  else
@@ -56,7 +72,10 @@ void InitializePlatformInterceptors();
 #    define ASAN_INTERCEPT_SWAPCONTEXT 0
 #  endif
 
-#  if !SANITIZER_WINDOWS
+// Sanitizer on AIX is currently unable to retrieve the address
+// of the real siglongjump (or an alternative thereto).
+// TODO: Consider intercepting sigsetjmpx on AIX.
+#  if !SANITIZER_WINDOWS && !SANITIZER_AIX
 #    define ASAN_INTERCEPT_SIGLONGJMP 1
 #  else
 #    define ASAN_INTERCEPT_SIGLONGJMP 0
@@ -84,7 +103,10 @@ void InitializePlatformInterceptors();
 #    define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 0
 #  endif
 
-#  if !SANITIZER_WINDOWS
+// Clang on AIX neither uses `__cxa_atexit` nor links against a library with
+// such.
+// TODO: Consider intercepting `atexit` and `unatexit` on AIX.
+#  if !SANITIZER_WINDOWS && !SANITIZER_AIX
 #    define ASAN_INTERCEPT___CXA_ATEXIT 1
 #  else
 #    define ASAN_INTERCEPT___CXA_ATEXIT 0

diff  --git a/compiler-rt/lib/asan/asan_malloc_linux.cpp b/compiler-rt/lib/asan/asan_malloc_linux.cpp
index add57318785be..b54e38baf0b5f 100644
--- a/compiler-rt/lib/asan/asan_malloc_linux.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_linux.cpp
@@ -15,7 +15,7 @@
 
 #include "sanitizer_common/sanitizer_platform.h"
 #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
-    SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU
+    SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_HAIKU || SANITIZER_AIX
 
 #  include "asan_allocator.h"
 #  include "asan_interceptors.h"

diff  --git a/compiler-rt/lib/interception/interception_aix.cpp b/compiler-rt/lib/interception/interception_aix.cpp
index 953bbad96eb47..a6cc4f7498f44 100644
--- a/compiler-rt/lib/interception/interception_aix.cpp
+++ b/compiler-rt/lib/interception/interception_aix.cpp
@@ -17,16 +17,61 @@
 #if SANITIZER_AIX
 
 #  include <dlfcn.h>  // for dlsym()
+#  include <stddef.h>  // for size_t
+
+#  if SANITIZER_WORDSIZE == 64
+#    define STRCPY_STR "___strcpy64"
+#    define MEMCPY_STR "___memcpy64"
+#    define MEMMOVE_STR "___memmove64"
+#  else
+#    define STRCPY_STR "___strcpy"
+#    define MEMCPY_STR "___memcpy"
+#    define MEMMOVE_STR "___memmove"
+#  endif
 
 namespace __interception {
 
-static void *GetFuncAddr(const char *name, uptr wrapper_addr) {
-  // AIX dlsym can only defect the functions that are exported, so
-  // on AIX, we can not intercept some basic functions like memcpy.
+// These symbols cannot be used for indirect calls.
+char* ___strcpy(char*, const char*) __asm__(STRCPY_STR);
+char* ___memcpy(char*, const char*, size_t) __asm__(MEMCPY_STR);
+char* ___memmove(char*, const char*, size_t) __asm__(MEMMOVE_STR);
+
+static char* real_strcpy_wrapper(char* s1, const char* s2) {
+  return (char*)___strcpy(s1, s2);
+}
+
+static char* real_memcpy_wrapper(char* s1, const char* s2, size_t n) {
+  return (char*)___memcpy(s1, s2, n);
+}
+
+static char* real_memmove_wrapper(char* s1, const char* s2, size_t n) {
+  return (char*)___memmove(s1, s2, n);
+}
+
+static void* GetFuncAddr(const char* name, uptr wrapper_addr) {
   // FIXME: if we are going to ship dynamic asan library, we may need to search
   // all the loaded modules with RTLD_DEFAULT if RTLD_NEXT failed.
   void *addr = dlsym(RTLD_NEXT, name);
 
+  // AIX dlsym can only detect functions that are exported, so
+  // some basic functions like memcpy return null. In this case, we fall back
+  // to a corresponding internal libc symbol (for example, ___memcpy) if it's
+  // available and, otherwise, to the internal sanitizer function.
+  if (!addr) {
+    if (internal_strcmp(name, "strcpy") == 0)
+      addr = (void*)real_strcpy_wrapper;
+    else if (internal_strcmp(name, "strncpy") == 0)
+      addr = (void*)internal_strncpy;
+    else if (internal_strcmp(name, "strcat") == 0)
+      addr = (void*)internal_strcat;
+    else if (internal_strcmp(name, "strncat") == 0)
+      addr = (void*)internal_strncat;
+    else if (internal_strcmp(name, "memcpy") == 0)
+      addr = (void*)real_memcpy_wrapper;
+    else if (internal_strcmp(name, "memmove") == 0)
+      addr = (void*)real_memmove_wrapper;
+  }
+
   // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
   // We don't want to intercept the wrapper and have it point to itself.
   if ((uptr)addr == wrapper_addr)

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp
index 9318066afed20..ece768ec8dab6 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_libc.cpp
@@ -190,6 +190,14 @@ uptr internal_strlcat(char *dst, const char *src, uptr maxlen) {
   return dstlen + srclen;
 }
 
+char* internal_strcat(char* dst, const char* src) {
+  uptr len = internal_strlen(dst);
+  uptr i;
+  for (i = 0; src[i]; i++) dst[len + i] = src[i];
+  dst[len + i] = 0;
+  return dst;
+}
+
 char *internal_strncat(char *dst, const char *src, uptr n) {
   uptr len = internal_strlen(dst);
   uptr i;

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_libc.h b/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
index 1906569e2a5fc..2f7ec9249e340 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_libc.h
@@ -59,6 +59,7 @@ char *internal_strdup(const char *s);
 uptr internal_strlen(const char *s);
 uptr internal_strlcat(char *dst, const char *src, uptr maxlen);
 char *internal_strncat(char *dst, const char *src, uptr n);
+char* internal_strcat(char* dst, const char* src);
 int internal_strncmp(const char *s1, const char *s2, uptr n);
 uptr internal_strlcpy(char *dst, const char *src, uptr maxlen);
 char *internal_strncpy(char *dst, const char *src, uptr n);

diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
index ed60671014d5a..1b300bc7533b6 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -167,7 +167,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 
 #define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA)
-#define SANITIZER_INTERCEPT_STRCMP (SI_NOT_FUCHSIA && SI_NOT_AIX)
+#define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_STRSTR SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_STRCASESTR (SI_POSIX && SI_NOT_AIX)
 #define SANITIZER_INTERCEPT_STRTOK SI_NOT_FUCHSIA
@@ -179,8 +179,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID || SI_SOLARIS
 #define SANITIZER_INTERCEPT_STRCASECMP SI_POSIX
 #define SANITIZER_INTERCEPT_MEMSET 1
-#define SANITIZER_INTERCEPT_MEMMOVE SI_NOT_AIX
-#define SANITIZER_INTERCEPT_MEMCPY SI_NOT_AIX
+#define SANITIZER_INTERCEPT_MEMMOVE 1
+#define SANITIZER_INTERCEPT_MEMCPY 1
 #define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_BCMP \
   SANITIZER_INTERCEPT_MEMCMP &&  \


        


More information about the llvm-commits mailing list