Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1c2952c
[sanitizer_common] Implement interceptors for AIX
jakeegan Mar 18, 2025
549b134
Define SANITIZER_AIX temporarily to build
jakeegan Mar 24, 2025
d3301a3
Revert "Define SANITIZER_AIX temporarily to build"
jakeegan Mar 24, 2025
6ffa232
convert to preprocessor directives
jakeegan Mar 24, 2025
4890013
Fix formatting
jakeegan Apr 1, 2025
dcde670
Add asan interceptor part
jakeegan Apr 23, 2025
c254027
Merge branch 'main' into asan_common3
jakeegan Apr 27, 2025
878a567
Remove typo
jakeegan Apr 27, 2025
7cc64a1
Fix undeclared identifier
jakeegan Apr 27, 2025
4159aa9
Correct backslash mistake
jakeegan Apr 27, 2025
b0098db
Fix return
jakeegan Apr 27, 2025
b159f20
Fix formatting
jakeegan Apr 28, 2025
67317ad
Move misplaced endif
jakeegan Apr 28, 2025
16a2d81
Split code to different PRs
jakeegan May 5, 2025
0935ed2
Use proper naming convention
jakeegan May 5, 2025
30d1f12
Move return
jakeegan May 5, 2025
38a520d
Remove accidental change
jakeegan May 6, 2025
4c8cd38
Remove accidental change
jakeegan May 6, 2025
8ce7b54
Fix build fail
jakeegan May 6, 2025
fb70384
Address comments
jakeegan May 27, 2025
b024cac
Address comments
jakeegan May 27, 2025
b57eee8
Forgot __strdup
jakeegan May 27, 2025
c3ff763
Fix formatting
jakeegan May 27, 2025
ab72dfa
Swap to unsigned
jakeegan Jun 24, 2025
72b85c9
Update comments
jakeegan Jul 7, 2025
93a5093
Forgot siglongjmp
jakeegan Jul 7, 2025
ad0b183
Fix siglongjmp comment
jakeegan Jul 7, 2025
1b40995
Fix formatting
jakeegan Jul 7, 2025
b7d52db
Merge branch 'main' into asan_common3
jakeegan Nov 19, 2025
cab7b84
Merge branch 'main' into asan_common3
jakeegan Nov 20, 2025
18a60b9
Handle memmove too
jakeegan Dec 2, 2025
0048e02
Fix formatting
jakeegan Dec 2, 2025
54f6a42
Merge branch 'main' into asan_common3
jakeegan Dec 10, 2025
cb545f5
Fix formatting
jakeegan Dec 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion compiler-rt/lib/asan/asan_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -781,11 +781,17 @@ struct Allocator {
u8 chunk_state = atomic_load(&m->chunk_state, memory_order_acquire);
if (chunk_state != CHUNK_ALLOCATED)
ReportInvalidFree(old_ptr, chunk_state, stack);
CHECK_NE(REAL(memcpy), nullptr);
uptr memcpy_size = Min(new_size, m->UsedSize());
// If realloc() races with free(), we may start copying freed memory.
// However, we will report racy double-free later anyway.
#if !SANITIZER_AIX
CHECK_NE(REAL(memcpy), nullptr);
REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
#else
// AIX currently can't retrieve memcpy's address, we have to use
// internal_memcpy here.
Comment on lines +791 to +792
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).

internal_memcpy(new_ptr, old_ptr, memcpy_size);
#endif
Deallocate(old_ptr, 0, 0, stack, FROM_MALLOC);
}
return new_ptr;
Expand Down
57 changes: 49 additions & 8 deletions compiler-rt/lib/asan/asan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,18 @@ namespace __asan {
# define ASAN_READ_STRING(ctx, s, n) \
ASAN_READ_STRING_OF_LEN((ctx), (s), internal_strlen(s), (n))

static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
#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).

REAL(memcpy)(new_mem, s, length + 1);
# else
internal_memcpy(new_mem, s, length + 1);
# 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?

uptr maxlen) {
# if SANITIZER_INTERCEPT_STRNLEN
if (static_cast<bool>(REAL(strnlen)))
return REAL(strnlen)(s, maxlen);
# endif
Expand Down Expand Up @@ -282,7 +292,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);
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);

# else
return result ? 0 : *(uptr *)(thread);
# endif
});
}
if (result != 0) {
Expand Down Expand Up @@ -439,12 +454,14 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
#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
# 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?

INTERCEPTOR(void, _longjmp, void *env, int val) {
__asan_handle_no_return();
REAL(_longjmp)(env, val);
Expand Down Expand Up @@ -515,6 +532,7 @@ DEFINE_REAL(char*, index, const char *string, int c)

// For both strcat() and strncat() we need to check the validity of |to|
// argument irrespective of the |from| length.
# if ASAN_INTERCEPT_STRCAT
INTERCEPTOR(char *, strcat, char *to, const char *from) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, strcat);
Expand Down Expand Up @@ -554,7 +572,9 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, usize size) {
}
return REAL(strncat)(to, from, size);
}
# endif

# if ASAN_INTERCEPT_STRCPY
INTERCEPTOR(char *, strcpy, char *to, const char *from) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, strcpy);
Expand All @@ -576,6 +596,7 @@ INTERCEPTOR(char *, strcpy, char *to, const char *from) {
}
return REAL(strcpy)(to, from);
}
# endif

INTERCEPTOR(wchar_t*, wcscpy, wchar_t* to, const wchar_t* from) {
void* ctx;
Expand Down Expand Up @@ -617,7 +638,7 @@ INTERCEPTOR(char*, strdup, const char *s) {
GET_STACK_TRACE_MALLOC;
void *new_mem = asan_malloc(length + 1, &stack);
if (new_mem) {
REAL(memcpy)(new_mem, s, length + 1);
internal_or_real_memcpy(new_mem, s, length + 1);
}
return reinterpret_cast<char*>(new_mem);
}
Expand All @@ -635,12 +656,13 @@ INTERCEPTOR(char*, __strdup, const char *s) {
GET_STACK_TRACE_MALLOC;
void *new_mem = asan_malloc(length + 1, &stack);
if (new_mem) {
REAL(memcpy)(new_mem, s, length + 1);
internal_or_real_memcpy(new_mem, s, length + 1);
}
return reinterpret_cast<char*>(new_mem);
}
#endif // ASAN_INTERCEPT___STRDUP

# if ASAN_INTERCEPT_STRCPY
INTERCEPTOR(char*, strncpy, char *to, const char *from, usize size) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
Expand All @@ -653,6 +675,7 @@ INTERCEPTOR(char*, strncpy, char *to, const char *from, usize size) {
}
return REAL(strncpy)(to, from, size);
}
# endif

INTERCEPTOR(wchar_t*, wcsncpy, wchar_t* to, const wchar_t* from, uptr size) {
void* ctx;
Expand Down Expand Up @@ -778,7 +801,15 @@ static void AtCxaAtexit(void *unused) {
}
#endif

#if ASAN_INTERCEPT___CXA_ATEXIT
# if ASAN_INTERCEPT_EXIT
INTERCEPTOR(void, exit, int status) {
AsanInitFromRtl();
StopInitOrderChecking();
REAL(exit)(status);
}
# endif
Comment on lines +804 to +810
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.


# if ASAN_INTERCEPT___CXA_ATEXIT
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
void *dso_handle) {
if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
Expand Down Expand Up @@ -839,10 +870,14 @@ void InitializeAsanInterceptors() {
InitializeSignalInterceptors();

// Intercept str* functions.
# if ASAN_INTERCEPT_STRCAT
ASAN_INTERCEPT_FUNC(strcat);
ASAN_INTERCEPT_FUNC(strcpy);
ASAN_INTERCEPT_FUNC(strncat);
# endif
# if ASAN_INTERCEPT_STRCPY
ASAN_INTERCEPT_FUNC(strcpy);
ASAN_INTERCEPT_FUNC(strncpy);
# endif
ASAN_INTERCEPT_FUNC(strdup);

// Intercept wcs* functions.
Expand All @@ -867,7 +902,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);
Expand Down Expand Up @@ -934,7 +971,11 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(atexit);
#endif

#if ASAN_INTERCEPT_PTHREAD_ATFORK
# if ASAN_INTERCEPT_EXIT
ASAN_INTERCEPT_FUNC(exit);
# endif

# if ASAN_INTERCEPT_PTHREAD_ATFORK
ASAN_INTERCEPT_FUNC(pthread_atfork);
#endif

Expand Down
35 changes: 32 additions & 3 deletions compiler-rt/lib/asan/asan_interceptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,22 @@ void InitializePlatformInterceptors();
// 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)".

# 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
// 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.

# 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
Expand All @@ -56,7 +68,8 @@ void InitializePlatformInterceptors();
# define ASAN_INTERCEPT_SWAPCONTEXT 0
# 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.

# if !SANITIZER_WINDOWS && !SANITIZER_AIX
# define ASAN_INTERCEPT_SIGLONGJMP 1
# else
# define ASAN_INTERCEPT_SIGLONGJMP 0
Expand Down Expand Up @@ -84,12 +97,19 @@ void InitializePlatformInterceptors();
# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 0
# 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.

# if !SANITIZER_WINDOWS && !SANITIZER_AIX
# define ASAN_INTERCEPT___CXA_ATEXIT 1
# else
# define ASAN_INTERCEPT___CXA_ATEXIT 0
# 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?

# else
# define ASAN_INTERCEPT_EXIT 0
# endif

# if SANITIZER_NETBSD
# define ASAN_INTERCEPT_ATEXIT 1
# else
Expand All @@ -110,6 +130,15 @@ void InitializePlatformInterceptors();
# define ASAN_INTERCEPT_TRYJOIN 0
# endif

// AIX currently can't retrieve the address of strcat or strcpy
# if SANITIZER_AIX
# define ASAN_INTERCEPT_STRCAT 0
# define ASAN_INTERCEPT_STRCPY 0
# else
# define ASAN_INTERCEPT_STRCAT 1
# define ASAN_INTERCEPT_STRCPY 1
# endif

# if SANITIZER_LINUX && \
(defined(__arm__) || defined(__aarch64__) || defined(__i386__) || \
defined(__x86_64__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64)
Expand Down
30 changes: 20 additions & 10 deletions compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@

using namespace __asan;

// AIX currently can't retrieve memcpy's address, we have to use internal_memcpy
// here.
#if !SANITIZER_AIX
# define ASAN_MEMCPY_RETURN(to, from, size) REAL(memcpy)(to, from, size)
# define ASAN_MEMMOVE_RETURN(to, from, size) REAL(memmove)(to, from, size)
#else
# define ASAN_MEMCPY_RETURN(to, from, size) internal_memcpy(to, from, size)
# define ASAN_MEMMOVE_RETURN(to, from, size) internal_memmove(to, from, size)
#endif

// memcpy is called during __asan_init() from the internals of printf(...).
// We do not treat memcpy with to==from as a bug.
// See http://llvm.org/bugs/show_bug.cgi?id=11763.
Expand All @@ -36,7 +46,7 @@ using namespace __asan;
} else if (UNLIKELY(!AsanInited())) { \
return internal_memcpy(to, from, size); \
} \
return REAL(memcpy)(to, from, size); \
return ASAN_MEMCPY_RETURN(to, from, size); \
} while (0)

// memset is called inside Printf.
Expand All @@ -50,15 +60,15 @@ using namespace __asan;
return REAL(memset)(block, c, size); \
} while (0)

#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \
do { \
if (LIKELY(replace_intrin_cached)) { \
ASAN_READ_RANGE(ctx, from, size); \
ASAN_WRITE_RANGE(ctx, to, size); \
} else if (UNLIKELY(!AsanInited())) { \
return internal_memmove(to, from, size); \
} \
return REAL(memmove)(to, from, size); \
#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \
do { \
if (LIKELY(replace_intrin_cached)) { \
ASAN_READ_RANGE(ctx, from, size); \
ASAN_WRITE_RANGE(ctx, to, size); \
} else if (UNLIKELY(!AsanInited())) { \
return internal_memmove(to, from, size); \
} \
return ASAN_MEMMOVE_RETURN(to, from, size); \
} while (0)

void *__asan_memcpy(void *to, const void *from, uptr size) {
Expand Down
20 changes: 19 additions & 1 deletion compiler-rt/lib/asan/asan_malloc_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -61,6 +61,24 @@ INTERCEPTOR(void, cfree, void *ptr) {
}
#endif // SANITIZER_INTERCEPT_CFREE

# if SANITIZER_AIX
INTERCEPTOR(void*, vec_malloc, uptr size) {
if (DlsymAlloc::Use())
return DlsymAlloc::Allocate(size);
AsanInitFromRtl();
GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}

INTERCEPTOR(void*, vec_calloc, uptr nmemb, uptr size) {
if (DlsymAlloc::Use())
return DlsymAlloc::Callocate(nmemb, size);
AsanInitFromRtl();
GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
# endif

INTERCEPTOR(void*, malloc, uptr size) {
if (DlsymAlloc::Use())
return DlsymAlloc::Allocate(size);
Expand Down