Skip to content

Conversation

@jakeegan
Copy link
Member

@jakeegan jakeegan commented Mar 18, 2025

Adjust asan interceptor support 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: #138916

@github-actions
Copy link

github-actions bot commented Mar 18, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@jakeegan jakeegan changed the title [sanitizer_common] Implement interceptors for AIX [sanitizer_common] Implement address sanitizer on AIX: interceptors (5/n) Mar 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 24, 2025

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

Author: Jake Egan (jakeegan)

Changes

Builds on the effort to support AIX in sanitizer_common/asan. Intercepting functions in shared libraries is not supported on AIX yet.

Previous PR: #131868


Patch is 20.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/131870.diff

9 Files Affected:

  • (modified) compiler-rt/lib/interception/CMakeLists.txt (+2)
  • (modified) compiler-rt/lib/interception/interception.h (+17-2)
  • (added) compiler-rt/lib/interception/interception_aix.cpp (+45)
  • (added) compiler-rt/lib/interception/interception_aix.h (+36)
  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc (+42-12)
  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc (+2)
  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc (+2)
  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h (+33-19)
  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h (+1-1)
diff --git a/compiler-rt/lib/interception/CMakeLists.txt b/compiler-rt/lib/interception/CMakeLists.txt
index fe7fa27fbc78b..57c8c8ba20141 100644
--- a/compiler-rt/lib/interception/CMakeLists.txt
+++ b/compiler-rt/lib/interception/CMakeLists.txt
@@ -1,6 +1,7 @@
 # Build for the runtime interception helper library.
 
 set(INTERCEPTION_SOURCES
+  interception_aix.cpp
   interception_linux.cpp
   interception_mac.cpp
   interception_win.cpp
@@ -9,6 +10,7 @@ set(INTERCEPTION_SOURCES
 
 set(INTERCEPTION_HEADERS
   interception.h
+  interception_aix.h
   interception_linux.h
   interception_mac.h
   interception_win.h
diff --git a/compiler-rt/lib/interception/interception.h b/compiler-rt/lib/interception/interception.h
index 3cb6b446638e0..3a20cfb04dcd6 100644
--- a/compiler-rt/lib/interception/interception.h
+++ b/compiler-rt/lib/interception/interception.h
@@ -19,7 +19,7 @@
 
 #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_APPLE &&    \
     !SANITIZER_NETBSD && !SANITIZER_WINDOWS && !SANITIZER_FUCHSIA && \
-    !SANITIZER_SOLARIS
+    !SANITIZER_SOLARIS && !SANITIZER_AIX
 #  error "Interception doesn't work on this operating system."
 #endif
 
@@ -168,6 +168,16 @@ const interpose_substitution substitution_##func_name[]             \
     extern "C" ret_type func(__VA_ARGS__);
 # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...)  \
     extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__);
+#elif SANITIZER_AIX
+#  define WRAP(x) __interceptor_##x
+#  define TRAMPOLINE(x) WRAP(x)
+// # define WRAPPER_NAME(x) "__interceptor_" #x
+#  define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
+// AIX's linker will not select the weak symbol, so don't use weak for the
+// interceptors.
+#  define DECLARE_WRAPPER(ret_type, func, ...) \
+    extern "C" ret_type func(__VA_ARGS__)      \
+        __attribute__((alias("__interceptor_" #func), visibility("default")));
 #elif !SANITIZER_FUCHSIA  // LINUX, FREEBSD, NETBSD, SOLARIS
 # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
 # if ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT
@@ -367,7 +377,12 @@ inline void DoesNotSupportStaticLinking() {}
 
 #define INCLUDED_FROM_INTERCEPTION_LIB
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
+#if SANITIZER_AIX
+# include "interception_aix.h"
+# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_AIX(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) INTERCEPT_FUNCTION_AIX(func)
+
+#elif SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
     SANITIZER_SOLARIS
 
 # include "interception_linux.h"
diff --git a/compiler-rt/lib/interception/interception_aix.cpp b/compiler-rt/lib/interception/interception_aix.cpp
new file mode 100644
index 0000000000000..953bbad96eb47
--- /dev/null
+++ b/compiler-rt/lib/interception/interception_aix.cpp
@@ -0,0 +1,45 @@
+//===-- interception_aix.cpp ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// AIX-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#include "interception.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+#if SANITIZER_AIX
+
+#  include <dlfcn.h>  // for dlsym()
+
+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.
+  // 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);
+
+  // 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)
+    addr = nullptr;
+  return addr;
+}
+
+bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
+                       uptr wrapper) {
+  void *addr = GetFuncAddr(name, wrapper);
+  *ptr_to_real = (uptr)addr;
+  return addr && (func == wrapper);
+}
+
+}  // namespace __interception
+#endif  // SANITIZER_AIX
diff --git a/compiler-rt/lib/interception/interception_aix.h b/compiler-rt/lib/interception/interception_aix.h
new file mode 100644
index 0000000000000..08d17caeb6a8d
--- /dev/null
+++ b/compiler-rt/lib/interception/interception_aix.h
@@ -0,0 +1,36 @@
+//===-- interception_aix.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// AIX-specific interception methods.
+//===----------------------------------------------------------------------===//
+
+#if SANITIZER_AIX
+
+#  if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
+#    error \
+        "interception_aix.h should be included from interception library only"
+#  endif
+
+#  ifndef INTERCEPTION_AIX_H
+#    define INTERCEPTION_AIX_H
+
+namespace __interception {
+bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
+                       uptr wrapper);
+}  // namespace __interception
+
+#    define INTERCEPT_FUNCTION_AIX(func)                \
+      ::__interception::InterceptFunction(              \
+          #func, (::__interception::uptr *)&REAL(func), \
+          (::__interception::uptr) & (func),            \
+          (::__interception::uptr)&WRAP(func))
+
+#  endif  // INTERCEPTION_AIX_H
+#endif    // SANITIZER_AIX
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 24a8a2d4dc55b..35876084f8107 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -480,7 +480,7 @@ INTERCEPTOR(char*, textdomain, const char *domainname) {
 #define INIT_TEXTDOMAIN
 #endif
 
-#if SANITIZER_INTERCEPT_STRCMP || SANITIZER_INTERCEPT_MEMCMP
+#if SANITIZER_INTERCEPT_MEMCMP
 static inline int CharCmpX(unsigned char c1, unsigned char c2) {
   return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
 }
@@ -953,7 +953,7 @@ INTERCEPTOR(double, frexp, double x, int *exp) {
 #define INIT_FREXP
 #endif  // SANITIZER_INTERCEPT_FREXP
 
-#if SANITIZER_INTERCEPT_FREXPF_FREXPL
+#if SANITIZER_INTERCEPT_FREXPF
 INTERCEPTOR(float, frexpf, float x, int *exp) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, frexpf, x, exp);
@@ -963,6 +963,12 @@ INTERCEPTOR(float, frexpf, float x, int *exp) {
   return res;
 }
 
+#define INIT_FREXPF COMMON_INTERCEPT_FUNCTION(frexpf);
+#else
+#define INIT_FREXPF
+#endif
+
+#if SANITIZER_INTERCEPT_FREXPL
 INTERCEPTOR(long double, frexpl, long double x, int *exp) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, frexpl, x, exp);
@@ -972,12 +978,10 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) {
   return res;
 }
 
-#define INIT_FREXPF_FREXPL           \
-  COMMON_INTERCEPT_FUNCTION(frexpf); \
-  COMMON_INTERCEPT_FUNCTION_LDBL(frexpl)
+#define INIT_FREXPL COMMON_INTERCEPT_FUNCTION_LDBL(frexpl)
 #else
-#define INIT_FREXPF_FREXPL
-#endif  // SANITIZER_INTERCEPT_FREXPF_FREXPL
+#define INIT_FREXPL
+#endif
 
 #if SI_POSIX
 static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec,
@@ -1346,7 +1350,8 @@ INTERCEPTOR(unsigned long, time, unsigned long *t) {
 #if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
 static void unpoison_tm(void *ctx, __sanitizer_tm *tm) {
   COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
-#if !SANITIZER_SOLARIS
+// AIX tm struct does not have tm_zone field.
+#if !SANITIZER_SOLARIS && !SANITIZER_AIX
   if (tm->tm_zone) {
     // Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone
     // can point to shared memory and tsan would report a data race.
@@ -1731,8 +1736,10 @@ INTERCEPTOR(int, __vsprintf_chk, char *str, int flag, SIZE_T size_to,
 VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap)
 #endif
 
+#if SANITIZER_INTERCEPT_VASPRINTF
 INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap)
 VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap)
+#endif
 
 #if SANITIZER_INTERCEPT_ISOC99_PRINTF
 INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap)
@@ -1783,8 +1790,10 @@ INTERCEPTOR(int, __snprintf_chk, char *str, SIZE_T size, int flag,
 FORMAT_INTERCEPTOR_IMPL(__snprintf_chk, vsnprintf, str, size, format)
 #endif
 
+#if SANITIZER_INTERCEPT_ASPRINTF
 INTERCEPTOR(int, asprintf, char **strp, const char *format, ...)
 FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format)
+#endif
 
 #if SANITIZER_INTERCEPT_ISOC99_PRINTF
 INTERCEPTOR(int, __isoc99_printf, const char *format, ...)
@@ -1807,17 +1816,29 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size,
 #endif  // SANITIZER_INTERCEPT_PRINTF
 
 #if SANITIZER_INTERCEPT_PRINTF
+#if SANITIZER_AIX
+#define INIT_PRINTF                     \
+  COMMON_INTERCEPT_FUNCTION_LDBL(printf);    \
+  COMMON_INTERCEPT_FUNCTION_LDBL(sprintf);   \
+  COMMON_INTERCEPT_FUNCTION_LDBL(snprintf);  \
+  COMMON_INTERCEPT_FUNCTION_LDBL(fprintf);   \
+  COMMON_INTERCEPT_FUNCTION_LDBL(vprintf);   \
+  COMMON_INTERCEPT_FUNCTION_LDBL(vsprintf);  \
+  COMMON_INTERCEPT_FUNCTION_LDBL(vsnprintf); \
+  COMMON_INTERCEPT_FUNCTION_LDBL(vfprintf);
+#else
 #define INIT_PRINTF                     \
   COMMON_INTERCEPT_FUNCTION_LDBL(printf);    \
   COMMON_INTERCEPT_FUNCTION_LDBL(sprintf);   \
   COMMON_INTERCEPT_FUNCTION_LDBL(snprintf);  \
-  COMMON_INTERCEPT_FUNCTION_LDBL(asprintf);  \
   COMMON_INTERCEPT_FUNCTION_LDBL(fprintf);   \
   COMMON_INTERCEPT_FUNCTION_LDBL(vprintf);   \
   COMMON_INTERCEPT_FUNCTION_LDBL(vsprintf);  \
   COMMON_INTERCEPT_FUNCTION_LDBL(vsnprintf); \
+  COMMON_INTERCEPT_FUNCTION_LDBL(asprintf);  \
   COMMON_INTERCEPT_FUNCTION_LDBL(vasprintf); \
   COMMON_INTERCEPT_FUNCTION_LDBL(vfprintf);
+#endif
 #else
 #define INIT_PRINTF
 #endif
@@ -3901,7 +3922,11 @@ INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) {
   if (res != ((SIZE_T)-1)) {
     CHECK_LE(res, sizeof(local_dest));
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res);
-    REAL(memcpy)(dest, local_dest, res);
+#if !SANITIZER_AIX
+      REAL(memcpy)(dest, local_dest, res);
+#else
+      internal_memcpy(dest, local_dest, res);
+#endif
   }
   return res;
 }
@@ -3923,7 +3948,11 @@ INTERCEPTOR(int, wctomb, char *dest, wchar_t src) {
   if (res != -1) {
     CHECK_LE(res, sizeof(local_dest));
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res);
-    REAL(memcpy)(dest, local_dest, res);
+#if !SANITIZER_AIX
+      REAL(memcpy)(dest, local_dest, res);
+#else
+      internal_memcpy(dest, local_dest, res);
+#endif
   }
   return res;
 }
@@ -10329,7 +10358,8 @@ static void InitializeCommonInterceptors() {
   INIT_PRINTF_L;
   INIT_ISOC99_PRINTF;
   INIT_FREXP;
-  INIT_FREXPF_FREXPL;
+  INIT_FREXPF;
+  INIT_FREXPL;
   INIT_GETPWNAM_AND_FRIENDS;
   INIT_GETPWNAM_R_AND_FRIENDS;
   INIT_GETPWENT;
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
index 49ec4097c900b..5b23039954a43 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -73,7 +73,9 @@ static void ioctl_table_fill() {
   _(TIOCNXCL, NONE, 0);
   _(TIOCOUTQ, WRITE, sizeof(int));
   _(TIOCPKT, READ, sizeof(int));
+#if !SANITIZER_AIX
   _(TIOCSCTTY, NONE, 0);
+#endif
   _(TIOCSETD, READ, sizeof(int));
   _(TIOCSPGRP, READ, pid_t_sz);
   _(TIOCSTI, READ, sizeof(char));
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc
index 1565a494140f6..e542a6c7b438a 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc
@@ -36,6 +36,8 @@
 #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
 #elif SANITIZER_WINDOWS64
 #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
+#elif SANITIZER_AIX
+#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 0
 #else
 #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE 1
 #endif  // SANITIZER_APPLE
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
index febd233bb1e3c..43a37037c971d 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -139,6 +139,12 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 #define SI_SOLARIS 0
 #endif
 
+#if SANITIZER_AIX
+#define SI_NOT_AIX 0
+#else
+#define SI_NOT_AIX 1
+#endif
+
 #if SANITIZER_SOLARIS32
 #define SI_SOLARIS32 1
 #else
@@ -159,20 +165,20 @@ 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
+#define SANITIZER_INTERCEPT_STRCMP (SI_NOT_FUCHSIA && SI_NOT_AIX)
 #define SANITIZER_INTERCEPT_STRSTR SI_NOT_FUCHSIA
-#define SANITIZER_INTERCEPT_STRCASESTR SI_POSIX
+#define SANITIZER_INTERCEPT_STRCASESTR (SI_POSIX && SI_NOT_AIX)
 #define SANITIZER_INTERCEPT_STRTOK SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_STRCHR SI_NOT_FUCHSIA
-#define SANITIZER_INTERCEPT_STRCHRNUL SI_POSIX_NOT_MAC
+#define SANITIZER_INTERCEPT_STRCHRNUL (SI_POSIX_NOT_MAC && SI_NOT_AIX)
 #define SANITIZER_INTERCEPT_STRRCHR SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_STRSPN SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_STRPBRK SI_NOT_FUCHSIA
 #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 1
-#define SANITIZER_INTERCEPT_MEMCPY 1
+#define SANITIZER_INTERCEPT_MEMMOVE SI_NOT_AIX
+#define SANITIZER_INTERCEPT_MEMCPY SI_NOT_AIX
 #define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA
 #define SANITIZER_INTERCEPT_BCMP \
   SANITIZER_INTERCEPT_MEMCMP &&  \
@@ -231,6 +237,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 #define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC
 
 #ifndef SANITIZER_INTERCEPT_PRINTF
+#define SANITIZER_INTERCEPT_ASPRINTF SI_NOT_AIX
+#define SANITIZER_INTERCEPT_VASPRINTF SI_NOT_AIX
 #define SANITIZER_INTERCEPT_PRINTF SI_POSIX
 #define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
 #define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC
@@ -239,8 +247,10 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 #define SANITIZER_INTERCEPT___PRINTF_CHK \
   (SANITIZER_INTERCEPT_PRINTF && SI_GLIBC)
 
-#define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA
-#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX
+// AIX libc does not export FREXP and FREXP.
+#define SANITIZER_INTERCEPT_FREXP (SI_NOT_FUCHSIA && SI_NOT_AIX)
+#define SANITIZER_INTERCEPT_FREXPF (SI_POSIX && SI_NOT_AIX)
+#define SANITIZER_INTERCEPT_FREXPL SI_POSIX
 
 #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX
 #define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
@@ -289,7 +299,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 #define SANITIZER_INTERCEPT_ACCEPT4 \
   (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_PACCEPT SI_NETBSD
-#define SANITIZER_INTERCEPT_MODF SI_POSIX
+#define SANITIZER_INTERCEPT_MODF (SI_POSIX && SI_NOT_AIX)
 #define SANITIZER_INTERCEPT_RECVMSG SI_POSIX
 #define SANITIZER_INTERCEPT_SENDMSG SI_POSIX
 #define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX
@@ -324,8 +334,9 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 #define SANITIZER_INTERCEPT___WCSXFRM_L SI_LINUX
 #define SANITIZER_INTERCEPT_WCSNRTOMBS \
   (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_WCRTOMB \
-  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_WCRTOMB                                           \
+  (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS || \
+   !SI_NOT_AIX)
 #define SANITIZER_INTERCEPT_WCTOMB \
   (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS
@@ -365,7 +376,8 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_STATFS \
   (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_STATFS64 SI_GLIBC && SANITIZER_HAS_STATFS64
+#define SANITIZER_INTERCEPT_STATFS64 \
+  ((SI_GLIBC || !SI_NOT_AIX) && SANITIZER_HAS_STATFS64)
 #define SANITIZER_INTERCEPT_STATVFS \
   (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
 #define SANITIZER_INTERCEPT_STATVFS64 SI_GLIBC
@@ -414,10 +426,10 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 #define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX
 #define SANITIZER_INTERCEPT_TEMPNAM SI_POSIX
 #define SANITIZER_INTERCEPT_SINCOS SI_LINUX || SI_SOLARIS
-#define SANITIZER_INTERCEPT_REMQUO SI_POSIX
-#define SANITIZER_INTERCEPT_REMQUOL (SI_POSIX && !SI_NETBSD)
-#define SANITIZER_INTERCEPT_LGAMMA SI_POSIX
-#define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD)
+#define SANITIZER_INTERCEPT_REMQUO (SI_POSIX && SI_NOT_AIX)
+#define SANITIZER_INTERCEPT_REMQUOL (SI_POSIX && !SI_NETBSD && SI_NOT_AIX)
+#define SANITIZER_INTERCEPT_LGAMMA (SI_POSIX && SI_NOT_AIX)
+#define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD && SI_NOT_AIX)
 #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
 #define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC
@@ -502,9 +514,11 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 #define SI_STAT_LINUX (SI_LINUX && __GLIBC_PREREQ(2, 33))
 #define SANITIZER_INTERCEPT_STAT                                        \
   (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD || SI_SOLARIS ||     \
-   SI_STAT_LINUX)
-#define SANITIZER_INTERCEPT_STAT64 SI_STAT_LINUX && SANITIZER_HAS_STAT64
-#define SANITIZER_INTERCEPT_LSTAT (SI_NETBSD || SI_FREEBSD || SI_STAT_LINUX)
+   SI_STAT_LINUX || !SI_NOT_AIX)
+#define SANITIZER_INTERCEPT_STAT64 \
+  ((SI_STAT_LINUX || !SI_NOT_AIX) && SANITIZER_HAS_STAT64)
+#define SANITIZER_INTERCEPT_LSTAT \
+  (SI_NETBSD || SI_FREEBSD || SI_STAT_LINUX || !SI_NOT_AIX)
 #define SANITIZER_INTERCEPT___XSTAT \
   ((!SANITIZER_INTERCEPT_STAT && SI_POSIX) || SI_STAT_LINUX)
 #define SANITIZER_INTERCEPT___XSTAT64 SI_GLIBC
@@ -572,7 +586,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
 #define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC
 #define SANITIZER_INTERCEPT_NETENT (SI_LINUX || SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_SETVBUF \
-  (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC)
+  (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC || !SI_NOT_AIX)
 #define SANITIZER_INTERCEPT_GETMNTINFO (SI_NETBSD || SI_FREEBSD || SI_MAC)
 #define SANITIZER_INTERCEPT_MI_VECTOR_HASH SI_NETBSD
 #define SANITIZER_INTERCEPT_GETVFSSTAT SI_NETBSD
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h b/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h
index 41e0613d6fc13..bda0f04687693 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_redefine_builtins.h
@@ -15,7 +15,7 @@
 #    define SANITIZER_REDEFINE_BUILTINS_H
 
 // The asm hack only works...
[truncated]

@jakeegan jakeegan requested a review from mandlebug March 24, 2025 17:42
@llvmbot llvmbot added the compiler-rt:asan Address sanitizer label Apr 24, 2025
@jakeegan jakeegan changed the title [sanitizer_common] Implement address sanitizer on AIX: interceptors (5/n) [sanitizer_common][asan] Implement address sanitizer on AIX: interceptors (5/n) Apr 24, 2025
@jakeegan jakeegan changed the title [sanitizer_common][asan] Implement address sanitizer on AIX: interceptors (5/n) [sanitizer_common][asan] Implement address sanitizer on AIX: interceptors (5/6) Apr 29, 2025
@jakeegan jakeegan requested a review from vitalybuka June 12, 2025 00:19
@MaskRay
Copy link
Member

MaskRay commented Jun 13, 2025

Can you add some description to the commit message? What's the interception strategy on AIX?

@jakeegan
Copy link
Member Author

Updated PR and description. If there's no more comments, I'll merge soon.

@vitalybuka vitalybuka requested a review from MaskRay June 24, 2025 17:39
Copy link
Collaborator

@hubert-reinterpretcast hubert-reinterpretcast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The patch is generally lacking in code comments to explain why things are different on AIX.

jakeegan added a commit that referenced this pull request Dec 5, 2025
Format the whole `asan_interceptors.h` file to prepare for some changes
in PR #131870.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Dec 5, 2025
Format the whole `asan_interceptors.h` file to prepare for some changes
in PR llvm/llvm-project#131870.
honeygoyal pushed a commit to honeygoyal/llvm-project that referenced this pull request Dec 9, 2025
Format the whole `asan_interceptors.h` file to prepare for some changes
in PR llvm#131870.
@jakeegan
Copy link
Member Author

Rebased the PR after the file asan_interceptors.h was reformatted. Are there any further comments/reviews?

Comment on lines +791 to +792
// AIX currently can't retrieve memcpy's address, we have to use
// internal_memcpy here.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment as written is misleading: it implies that being unable to retrieve an address for the real memcpy as a member of a shared library (which, afaik, is not something that we plan to change) necessarily means that we have to use internal_memcpy (i.e., there are no other options).

Perhaps change this comment to reflect any future plans to use ___memcpy on AIX? Better yet: Update this PR to make use of ___memcpy (which is what the memcpy wrapper that AIX libc provides for static linking forwards to).

# endif
}

[[maybe_unused]] static inline uptr MaybeRealStrnlen(const char* s,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for the addition of [[maybe_unused]] here as part of this PR?

result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
// AIX pthread_t is unsigned int.
# if SANITIZER_AIX
return result ? 0 : *(unsigned*)(thread);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Match style with similar line below.

Suggested change
return result ? 0 : *(unsigned*)(thread);
return result ? 0 : *(unsigned *)(thread);

# endif

#if ASAN_INTERCEPT__LONGJMP
# if ASAN_INTERCEPT__LONGJMP
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a formatting change that should have happened on a separate PR?

#if SANITIZER_INTERCEPT_STRNLEN
static inline void internal_or_real_memcpy(void* new_mem, const char* s,
uptr length) {
# if SANITIZER_INTERCEPT_MEMCPY
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the logical reason to use SANITIZER_INTERCEPT_MEMCPY here as

  • it is unexplained why enabling interception for memcpy means we cannot use internal_memcpy in this context, and
  • this PR is supposed to be an AIX-specific change, so why have a change that reads as being platform-agnostic?

SANITIZER_INTERCEPT_MEMCPY was added in d7c6cad, which basically makes it an alias of SI_NOT_AIX. I believe this should just use SI_NOT_AIX directly (with a TODO to remove this function when REAL(memcpy) is set up to work on AIX).

Comment on lines +804 to +810
# if ASAN_INTERCEPT_EXIT
INTERCEPTOR(void, exit, int status) {
AsanInitFromRtl();
StopInitOrderChecking();
REAL(exit)(status);
}
# endif
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe split adding new interceptors out to a separate PR and focus this PR on compatibility changes to existing sanitizer code.

// really defined to replace libc functions.
#if !SANITIZER_FUCHSIA

// AIX currently can't retrieve the address of longjmp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add TODO comment to investigate using longjmpx (and also intercepting it).

Also, for all "AIX currently can't retrieve the address of [ ... ]" comments, the correct phrasing is "Sanitizer on AIX is currently unable to retrieve the address of the real [ ... ] (or an alternative thereto)".

// intercepted on a given platform.
# if !SANITIZER_WINDOWS
# define ASAN_INTERCEPT__LONGJMP 1
// AIX currently can't retrieve the address of _longjmp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add TODO comment re: _longjmpx.

# endif

# if !SANITIZER_WINDOWS
// AIX currently can't retrieve the address of siglongjmp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add TODO comment re: sigsetjmpx.

# endif

# if !SANITIZER_WINDOWS
// AIX currently can't retrieve the address of __cxa_atexit
Copy link
Collaborator

@hubert-reinterpretcast hubert-reinterpretcast Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// AIX currently can't retrieve the address of __cxa_atexit
// Clang on AIX neither uses `__cxa_atexit` nor links against a library with
// such.
// TODO: Consider intercepting `atexit` and `unatexit` on AIX.

# endif

# if SANITIZER_AIX
# define ASAN_INTERCEPT_EXIT 1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is special about AIX that we need it for AIX and not other platforms? What happens on AIX if we don't have this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants