[compiler-rt] [compiler-rt][asan] _aligned_malloc/_aligned_free interception. (PR #82049)

David CARLIER via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 30 19:58:33 PDT 2026


https://github.com/devnexen updated https://github.com/llvm/llvm-project/pull/82049

>From c2fa6fd3482b46a38b8041b652a9d9dcdc57c628 Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen at gmail.com>
Date: Fri, 16 Feb 2024 22:08:25 +0000
Subject: [PATCH 1/5] [compiler-rt][asan] _aligned_malloc/_aligned_free
 interception.

---
 compiler-rt/lib/asan/asan_malloc_win.cpp      | 42 ++++++++++++++++++-
 .../lib/asan/asan_malloc_win_thunk.cpp        | 19 +++++++++
 .../TestCases/Windows/aligned_mallocs.cpp     |  6 ++-
 3 files changed, 64 insertions(+), 3 deletions(-)

diff --git a/compiler-rt/lib/asan/asan_malloc_win.cpp b/compiler-rt/lib/asan/asan_malloc_win.cpp
index abb1b496d1b40..dad3b06358977 100644
--- a/compiler-rt/lib/asan/asan_malloc_win.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win.cpp
@@ -151,6 +151,33 @@ __declspec(noinline) void *_recalloc_base(void *p, size_t n, size_t elem_size) {
   return _recalloc(p, n, elem_size);
 }
 
+__declspec(noinline) void *_aligned_malloc(size_t size, size_t alignment) {
+  GET_STACK_TRACE_MALLOC;
+  return asan_aligned_alloc(alignment, size, &stack);
+}
+
+__declspec(noinline) void *_aligned_realloc(void *p, size_t size,
+                                            size_t alignment) {
+  GET_STACK_TRACE_MALLOC;
+  void *n = asan_aligned_alloc(alignment, size, &stack);
+  if (n) {
+    size_t osize = _msize(p);
+    REAL(memcpy)(n, p, Min<size_t>(osize, size));
+    free(p);
+  }
+
+  return n;
+}
+
+__declspec(noinline) void _aligned_free(void *p) { free(p); }
+
+__declspec(noinline) size_t _aligned_msize(void *p) {
+  GET_CURRENT_PC_BP_SP;
+  (void)sp;
+
+  return asan_malloc_usable_size(p, pc, bp);
+}
+
 __declspec(noinline) void *_expand(void *memblock, size_t size) {
   // _expand is used in realloc-like functions to resize the buffer if possible.
   // We don't want memory to stand still while resizing buffers, so return 0.
@@ -182,8 +209,15 @@ __declspec(dllexport) void *__cdecl __asan_recalloc(void *const ptr,
   return _recalloc(ptr, nmemb, size);
 }
 
-// TODO(timurrrr): Might want to add support for _aligned_* allocation
-// functions to detect a bit more bugs.  Those functions seem to wrap malloc().
+__declspec(dllexport) void *__cdecl __asan_aligned_malloc(
+    const size_t size, const size_t alignment) {
+  return _aligned_malloc(size, alignment);
+}
+
+__declspec(dllexport) void *__cdecl __asan_aligned_realloc(
+    void *const ptr, const size_t size, const size_t alignment) {
+  return _aligned_realloc(ptr, size, alignment);
+}
 
 int _CrtDbgReport(int, const char*, int,
                   const char*, const char*, ...) {
@@ -524,6 +558,10 @@ void ReplaceSystemMalloc() {
   TryToOverrideFunction("_msize_base", (uptr)_msize);
   TryToOverrideFunction("_expand", (uptr)_expand);
   TryToOverrideFunction("_expand_base", (uptr)_expand);
+  TryToOverrideFunction("_aligned_malloc", (uptr)_aligned_malloc);
+  TryToOverrideFunction("_aligned_realloc", (uptr)_aligned_realloc);
+  TryToOverrideFunction("_aligned_free", (uptr)_aligned_free);
+  TryToOverrideFunction("_aligned_msize", (uptr)_aligned_msize);
 
   if (flags()->windows_hook_rtl_allocators) {
     ASAN_INTERCEPT_FUNC(HeapSize);
diff --git a/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
index 9cc00913177ea..9dbb8dae40f45 100644
--- a/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
@@ -33,6 +33,11 @@ __declspec(dllimport) void *__cdecl __asan_realloc(void *const ptr,
 __declspec(dllimport) void *__cdecl __asan_recalloc(void *const ptr,
                                                     const size_t nmemb,
                                                     const size_t size);
+__declspec(dllimport) void *__cdecl __asan_aligned_malloc(
+    const size_t size, const size_t alignment);
+
+__declspec(dllimport) void *__cdecl __asan_aligned_realloc(
+    void *const ptr, const size_t size, const size_t alignment);
 
 // Avoid tailcall optimization to preserve stack frames.
 #  pragma optimize("", off)
@@ -141,6 +146,20 @@ STATIC_MALLOC_INTERFACE void *_expand_dbg(void *, size_t, int, const char *,
   return nullptr;
 }
 
+// _aligned
+STATIC_MALLOC_INTERFACE void *_aligned_malloc(size_t size, size_t alignment) {
+  return __asan_aligned_malloc(size, alignment);
+}
+
+STATIC_MALLOC_INTERFACE void *_aligned_realloc(void *ptr, size_t size,
+                                               size_t alignment) {
+  return __asan_aligned_realloc(ptr, size, alignment);
+}
+
+STATIC_MALLOC_INTERFACE void _aligned_free(void *ptr) { __asan_free(ptr); }
+
+STATIC_MALLOC_INTERFACE size_t _aligned_msize(void *ptr) { return _msize(ptr); }
+
 // We need to provide symbols for all the debug CRT functions if we decide to
 // provide any. Most of these functions make no sense under ASan and so we
 // make them no-ops.
diff --git a/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp b/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
index ee6ec4495e7c8..3d507afb610ad 100644
--- a/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_cl_asan %Od %s %Fe%t
-// RUN: %run %t
+// RUN: not %run %t 2>&1 | FileCheck %s
 
 #include <windows.h>
 
@@ -30,6 +30,10 @@ int main(void) {
   if (_aligned_msize(p, 128, 0) != 2048 * sizeof(int))
     return __LINE__;
   _aligned_free(p);
+  char *t = (char *)_aligned_malloc(128, 8);
+  t[-1] = 'a';
+  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
 
   return 0;
 }

>From 0071cebd5df14dde417a450cf14b66d6221504cc Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen at gmail.com>
Date: Mon, 18 Nov 2024 16:46:57 +0000
Subject: [PATCH 2/5] fix build and tests attempt

---
 .../lib/asan/asan_malloc_win_thunk.cpp        | 19 -------------------
 .../asan/asan_win_static_runtime_thunk.cpp    |  4 ++++
 .../TestCases/Windows/aligned_mallocs.cpp     |  8 ++++++++
 3 files changed, 12 insertions(+), 19 deletions(-)

diff --git a/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
index 9dbb8dae40f45..9cc00913177ea 100644
--- a/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
@@ -33,11 +33,6 @@ __declspec(dllimport) void *__cdecl __asan_realloc(void *const ptr,
 __declspec(dllimport) void *__cdecl __asan_recalloc(void *const ptr,
                                                     const size_t nmemb,
                                                     const size_t size);
-__declspec(dllimport) void *__cdecl __asan_aligned_malloc(
-    const size_t size, const size_t alignment);
-
-__declspec(dllimport) void *__cdecl __asan_aligned_realloc(
-    void *const ptr, const size_t size, const size_t alignment);
 
 // Avoid tailcall optimization to preserve stack frames.
 #  pragma optimize("", off)
@@ -146,20 +141,6 @@ STATIC_MALLOC_INTERFACE void *_expand_dbg(void *, size_t, int, const char *,
   return nullptr;
 }
 
-// _aligned
-STATIC_MALLOC_INTERFACE void *_aligned_malloc(size_t size, size_t alignment) {
-  return __asan_aligned_malloc(size, alignment);
-}
-
-STATIC_MALLOC_INTERFACE void *_aligned_realloc(void *ptr, size_t size,
-                                               size_t alignment) {
-  return __asan_aligned_realloc(ptr, size, alignment);
-}
-
-STATIC_MALLOC_INTERFACE void _aligned_free(void *ptr) { __asan_free(ptr); }
-
-STATIC_MALLOC_INTERFACE size_t _aligned_msize(void *ptr) { return _msize(ptr); }
-
 // We need to provide symbols for all the debug CRT functions if we decide to
 // provide any. Most of these functions make no sense under ASan and so we
 // make them no-ops.
diff --git a/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
index 46e0e90738f24..07b9aabededa2 100644
--- a/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
+++ b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
@@ -69,6 +69,10 @@ INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsncat);
 INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsncpy);
 INTERCEPT_LIBRARY_FUNCTION_ASAN(wcslen);
 INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsnlen);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(_aligned_malloc);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(_aligned_realloc);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(_aligned_free);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(_aligned_msize);
 
 // Note: Don't intercept strtol(l). They are supposed to set errno for out-of-
 // range values, but since the ASan runtime is linked against the dynamic CRT,
diff --git a/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp b/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
index 3d507afb610ad..47c7c2887a1c5 100644
--- a/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
@@ -30,6 +30,14 @@ int main(void) {
   if (_aligned_msize(p, 128, 0) != 2048 * sizeof(int))
     return __LINE__;
   _aligned_free(p);
+
+  char *y = (char *)malloc(1024);
+  char *u = (char *)realloc(y, 2048);
+  u[0] = 'a';
+  _aligned_free(u);
+  u = (char *)_aligned_offset_malloc(1024, 8, 0);
+  _aligned_free(u);
+
   char *t = (char *)_aligned_malloc(128, 8);
   t[-1] = 'a';
   // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]

>From 6204029b0feee7361bb6aa9e93d3701422b43774 Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen at gmail.com>
Date: Tue, 19 Nov 2024 21:04:06 +0000
Subject: [PATCH 3/5] adding few missing calls.

---
 compiler-rt/lib/asan/asan_malloc_win.cpp      | 67 ++++++++++++++++++-
 .../asan/asan_win_static_runtime_thunk.cpp    |  4 --
 .../TestCases/Windows/aligned_mallocs.cpp     |  2 +-
 3 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/compiler-rt/lib/asan/asan_malloc_win.cpp b/compiler-rt/lib/asan/asan_malloc_win.cpp
index dad3b06358977..09339ee18bf93 100644
--- a/compiler-rt/lib/asan/asan_malloc_win.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win.cpp
@@ -156,6 +156,10 @@ __declspec(noinline) void *_aligned_malloc(size_t size, size_t alignment) {
   return asan_aligned_alloc(alignment, size, &stack);
 }
 
+__declspec(noinline) void *_aligned_malloc_dbg(size_t size, size_t alignment) {
+  return _aligned_malloc(alignment, size);
+}
+
 __declspec(noinline) void *_aligned_realloc(void *p, size_t size,
                                             size_t alignment) {
   GET_STACK_TRACE_MALLOC;
@@ -169,7 +173,55 @@ __declspec(noinline) void *_aligned_realloc(void *p, size_t size,
   return n;
 }
 
-__declspec(noinline) void _aligned_free(void *p) { free(p); }
+__declspec(noinline) void *_aligned_realloc_dbg(void *p, size_t size,
+                                                size_t alignment) {
+  return _aligned_realloc(p, size, alignment);
+}
+
+__declspec(noinline) void *_aligned_recalloc(void *p, size_t nmemb, size_t size,
+                                             size_t alignment) {
+  const size_t total = nmemb * size;
+  if (total && total / size != nmemb)
+    return nullptr;
+  void *n = _aligned_realloc(p, total, alignment);
+  if (n)
+    REAL(memset)(n, 0, size);
+
+  return n;
+}
+
+__declspec(noinline) void *_aligned_recalloc_dbg(void *p, size_t nmemb,
+                                                 size_t size,
+                                                 size_t alignment) {
+  return _aligned_recalloc(p, nmemb, size, alignment);
+}
+
+__declspec(noinline) void *_aligned_offset_malloc(size_t size, size_t alignment,
+                                                  size_t offset) {
+  const size_t total = offset + size;
+  if (total && (total - offset) != size)
+    return nullptr;
+  void *p = _aligned_malloc(total, alignment);
+  if (p)
+    return ((u8 *)p) + offset;
+
+  return nullptr;
+}
+
+__declspec(noinline) void *_aligned_offset_malloc_dbg(size_t size,
+                                                      size_t alignment,
+                                                      size_t offset) {
+  return _aligned_offset_malloc(size, alignment, offset);
+}
+
+__declspec(noinline) void _aligned_free(void *p) {
+  void *b = const_cast<void *>(
+      __sanitizer_get_allocated_begin(const_cast<void *>(p)));
+  CHECK(b != nullptr && "invalid pointer");
+  free(b);
+}
+
+__declspec(noinline) void _aligned_free_dbg(void *p) { _aligned_free(p); }
 
 __declspec(noinline) size_t _aligned_msize(void *p) {
   GET_CURRENT_PC_BP_SP;
@@ -178,6 +230,10 @@ __declspec(noinline) size_t _aligned_msize(void *p) {
   return asan_malloc_usable_size(p, pc, bp);
 }
 
+__declspec(noinline) size_t _aligned_msize_dbg(void *p) {
+  return _aligned_msize(p);
+}
+
 __declspec(noinline) void *_expand(void *memblock, size_t size) {
   // _expand is used in realloc-like functions to resize the buffer if possible.
   // We don't want memory to stand still while resizing buffers, so return 0.
@@ -560,8 +616,17 @@ void ReplaceSystemMalloc() {
   TryToOverrideFunction("_expand_base", (uptr)_expand);
   TryToOverrideFunction("_aligned_malloc", (uptr)_aligned_malloc);
   TryToOverrideFunction("_aligned_realloc", (uptr)_aligned_realloc);
+  TryToOverrideFunction("_aligned_recalloc", (uptr)_aligned_recalloc);
   TryToOverrideFunction("_aligned_free", (uptr)_aligned_free);
   TryToOverrideFunction("_aligned_msize", (uptr)_aligned_msize);
+  TryToOverrideFunction("_aligned_malloc_dbg", (uptr)_aligned_malloc_dbg);
+  TryToOverrideFunction("_aligned_realloc_dbg", (uptr)_aligned_realloc_dbg);
+  TryToOverrideFunction("_aligned_recalloc_dbg", (uptr)_aligned_recalloc_dbg);
+  TryToOverrideFunction("_aligned_free_dbg", (uptr)_aligned_free_dbg);
+  TryToOverrideFunction("_aligned_msize_dbg", (uptr)_aligned_msize_dbg);
+  TryToOverrideFunction("_aligned_offset_malloc", (uptr)_aligned_offset_malloc);
+  TryToOverrideFunction("_aligned_offset_malloc_dbg",
+                        (uptr)_aligned_offset_malloc_dbg);
 
   if (flags()->windows_hook_rtl_allocators) {
     ASAN_INTERCEPT_FUNC(HeapSize);
diff --git a/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
index 07b9aabededa2..46e0e90738f24 100644
--- a/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
+++ b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
@@ -69,10 +69,6 @@ INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsncat);
 INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsncpy);
 INTERCEPT_LIBRARY_FUNCTION_ASAN(wcslen);
 INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsnlen);
-INTERCEPT_LIBRARY_FUNCTION_ASAN(_aligned_malloc);
-INTERCEPT_LIBRARY_FUNCTION_ASAN(_aligned_realloc);
-INTERCEPT_LIBRARY_FUNCTION_ASAN(_aligned_free);
-INTERCEPT_LIBRARY_FUNCTION_ASAN(_aligned_msize);
 
 // Note: Don't intercept strtol(l). They are supposed to set errno for out-of-
 // range values, but since the ASan runtime is linked against the dynamic CRT,
diff --git a/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp b/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
index 47c7c2887a1c5..6fdedea42bf04 100644
--- a/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
@@ -39,7 +39,7 @@ int main(void) {
   _aligned_free(u);
 
   char *t = (char *)_aligned_malloc(128, 8);
-  t[-1] = 'a';
+  t[-153] = 'a';
   // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
   // CHECK: WRITE of size 1 at [[ADDR]] thread T0
 

>From bf9dd9bd08157b2b6be955e28657a33f32ca9b37 Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen at gmail.com>
Date: Thu, 30 Jan 2025 19:02:10 +0000
Subject: [PATCH 4/5] (re)adding missing calls in win_thunk.

---
 compiler-rt/lib/asan/asan_malloc_win.cpp      |  2 +-
 .../lib/asan/asan_malloc_win_thunk.cpp        | 73 +++++++++++++++++++
 .../TestCases/Windows/aligned_mallocs.cpp     |  5 +-
 3 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/compiler-rt/lib/asan/asan_malloc_win.cpp b/compiler-rt/lib/asan/asan_malloc_win.cpp
index 09339ee18bf93..2060d1347608c 100644
--- a/compiler-rt/lib/asan/asan_malloc_win.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win.cpp
@@ -164,7 +164,7 @@ __declspec(noinline) void *_aligned_realloc(void *p, size_t size,
                                             size_t alignment) {
   GET_STACK_TRACE_MALLOC;
   void *n = asan_aligned_alloc(alignment, size, &stack);
-  if (n) {
+  if (n && p) {
     size_t osize = _msize(p);
     REAL(memcpy)(n, p, Min<size_t>(osize, size));
     free(p);
diff --git a/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
index 9cc00913177ea..c1f56515465a5 100644
--- a/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
@@ -34,6 +34,15 @@ __declspec(dllimport) void *__cdecl __asan_recalloc(void *const ptr,
                                                     const size_t nmemb,
                                                     const size_t size);
 
+__declspec(dllimport) void *__cdecl __asan_recalloc(void *const ptr,
+                                                    const size_t nmemb,
+                                                    const size_t size);
+__declspec(dllexport) void *__cdecl __asan_aligned_malloc(
+    const size_t size, const size_t alignment);
+
+__declspec(dllexport) void *__cdecl __asan_aligned_realloc(
+    void *const ptr, const size_t size, const size_t alignment);
+
 // Avoid tailcall optimization to preserve stack frames.
 #  pragma optimize("", off)
 
@@ -141,6 +150,70 @@ STATIC_MALLOC_INTERFACE void *_expand_dbg(void *, size_t, int, const char *,
   return nullptr;
 }
 
+// _aligned_malloc
+
+STATIC_MALLOC_INTERFACE void *_aligned_malloc(size_t size, size_t alignment) {
+  return __asan_aligned_malloc(size, alignment);
+}
+
+STATIC_MALLOC_INTERFACE void *_aligned_malloc_dbg(size_t size,
+                                                  size_t alignment) {
+  return _aligned_malloc(size, alignment);
+}
+
+// _aligned_realloc
+
+STATIC_MALLOC_INTERFACE void *_aligned_realloc(void *p, size_t size,
+                                               size_t alignment) {
+  return __asan_aligned_realloc(p, size, alignment);
+}
+
+STATIC_MALLOC_INTERFACE void *_aligned_realloc_dbg(void *p, size_t size,
+                                                   size_t alignment) {
+  return _aligned_realloc(p, size, alignment);
+}
+
+// _aligned_offset_malloc
+
+STATIC_MALLOC_INTERFACE void *_aligned_offset_malloc(size_t size,
+                                                     size_t alignment,
+                                                     size_t offset) {
+  const size_t total = offset + size;
+  if (total && (total - offset) != size)
+    return nullptr;
+  void *p = _aligned_malloc(total, alignment);
+  if (p)
+    return ((char *)p) + offset;
+
+  return nullptr;
+}
+
+STATIC_MALLOC_INTERFACE void *_aligned_offset_malloc_dbg(size_t size,
+                                                         size_t alignment,
+                                                         size_t offset) {
+  return _aligned_offset_malloc(size, alignment, offset);
+}
+
+// _aligned_free
+
+STATIC_MALLOC_INTERFACE void _aligned_free(void *p) {
+  void *b = const_cast<void *>(
+      __sanitizer_get_allocated_begin(const_cast<void *>(p)));
+  __asan_free(b);
+}
+
+STATIC_MALLOC_INTERFACE void _aligned_free_dbg(void *p) { _aligned_free(p); }
+
+// _aligned_msize
+
+STATIC_MALLOC_INTERFACE size_t _aligned_msize(void *p) {
+  return __asan_msize(p);
+}
+
+STATIC_MALLOC_INTERFACE size_t _aligned_msize_dbg(void *p) {
+  return __asan_msize(p);
+}
+
 // We need to provide symbols for all the debug CRT functions if we decide to
 // provide any. Most of these functions make no sense under ASan and so we
 // make them no-ops.
diff --git a/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp b/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
index 6fdedea42bf04..0fea1221f27ab 100644
--- a/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
@@ -40,8 +40,9 @@ int main(void) {
 
   char *t = (char *)_aligned_malloc(128, 8);
   t[-153] = 'a';
-  // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
-  // CHECK: WRITE of size 1 at [[ADDR]] thread T0
 
   return 0;
 }
+
+// CHECK: AddressSanitizer: access-violation on unknown address
+// CHECK: The signal is caused by a WRITE memory access.

>From eb0e72146b7bc65cfcd8b4c20372bb936cb9e920 Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen at gmail.com>
Date: Thu, 1 Oct 2026 03:58:02 +0100
Subject: [PATCH 5/5] fix remaining issues

---
 compiler-rt/lib/asan/asan_malloc_win.cpp      | 192 ++++++++++++------
 .../lib/asan/asan_malloc_win_thunk.cpp        | 134 +++++++-----
 .../TestCases/Windows/aligned_mallocs.cpp     |  42 +++-
 3 files changed, 251 insertions(+), 117 deletions(-)

diff --git a/compiler-rt/lib/asan/asan_malloc_win.cpp b/compiler-rt/lib/asan/asan_malloc_win.cpp
index 2060d1347608c..b9c72f487be7f 100644
--- a/compiler-rt/lib/asan/asan_malloc_win.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win.cpp
@@ -151,87 +151,137 @@ __declspec(noinline) void *_recalloc_base(void *p, size_t n, size_t elem_size) {
   return _recalloc(p, n, elem_size);
 }
 
-__declspec(noinline) void *_aligned_malloc(size_t size, size_t alignment) {
+__declspec(noinline) void* _aligned_malloc(size_t size, size_t alignment) {
   GET_STACK_TRACE_MALLOC;
-  return asan_aligned_alloc(alignment, size, &stack);
+  return asan_memalign(alignment, size, &stack);
 }
 
-__declspec(noinline) void *_aligned_malloc_dbg(size_t size, size_t alignment) {
-  return _aligned_malloc(alignment, size);
+__declspec(noinline) void* _aligned_malloc_dbg(size_t size, size_t alignment,
+                                               const char*, int) {
+  return _aligned_malloc(size, alignment);
 }
 
-__declspec(noinline) void *_aligned_realloc(void *p, size_t size,
-                                            size_t alignment) {
-  GET_STACK_TRACE_MALLOC;
-  void *n = asan_aligned_alloc(alignment, size, &stack);
-  if (n && p) {
-    size_t osize = _msize(p);
-    REAL(memcpy)(n, p, Min<size_t>(osize, size));
-    free(p);
-  }
+// The _aligned_offset_* family wants (p + offset) aligned rather than p, so
+// the returned pointer may be interior to the chunk. _aligned_free and
+// _aligned_msize map it back to the chunk start.
+__declspec(noinline) void* _aligned_offset_malloc(size_t size, size_t alignment,
+                                                  size_t offset) {
+  if (size && offset >= size)
+    return nullptr;
+  // Nothing to align in an empty block, and a padded one would hand out a
+  // pointer past the end of its chunk.
+  if (!size)
+    offset = 0;
+  // Let _aligned_malloc report the invalid alignment.
+  if (!IsPowerOfTwo(alignment))
+    return _aligned_malloc(size, alignment);
+  const size_t pad = RoundUpTo(offset, alignment) - offset;
+  if (size + pad < size)
+    return nullptr;
+  u8* p = (u8*)_aligned_malloc(size + pad, alignment);
+  return p ? p + pad : nullptr;
+}
 
-  return n;
+__declspec(noinline) void* _aligned_offset_malloc_dbg(size_t size,
+                                                      size_t alignment,
+                                                      size_t offset,
+                                                      const char*, int) {
+  return _aligned_offset_malloc(size, alignment, offset);
 }
 
-__declspec(noinline) void *_aligned_realloc_dbg(void *p, size_t size,
-                                                size_t alignment) {
-  return _aligned_realloc(p, size, alignment);
+__declspec(noinline) void _aligned_free(void* p) {
+  if (!p)
+    return;
+  // If p is not an ASan chunk, let free report it.
+  const void* b = __sanitizer_get_allocated_begin(p);
+  free(b ? const_cast<void*>(b) : p);
 }
 
-__declspec(noinline) void *_aligned_recalloc(void *p, size_t nmemb, size_t size,
-                                             size_t alignment) {
-  const size_t total = nmemb * size;
-  if (total && total / size != nmemb)
-    return nullptr;
-  void *n = _aligned_realloc(p, total, alignment);
-  if (n)
-    REAL(memset)(n, 0, size);
+__declspec(noinline) void _aligned_free_dbg(void* p) { _aligned_free(p); }
 
-  return n;
+__declspec(noinline) size_t _aligned_msize(void* p, size_t, size_t) {
+  GET_CURRENT_PC_BP_SP;
+  (void)sp;
+  const void* b = __sanitizer_get_allocated_begin(p);
+  if (!b)
+    return asan_malloc_usable_size(p, pc, bp);
+  return asan_malloc_usable_size(b, pc, bp) - ((u8*)p - (const u8*)b);
 }
 
-__declspec(noinline) void *_aligned_recalloc_dbg(void *p, size_t nmemb,
-                                                 size_t size,
-                                                 size_t alignment) {
-  return _aligned_recalloc(p, nmemb, size, alignment);
+__declspec(noinline) size_t _aligned_msize_dbg(void* p, size_t alignment,
+                                               size_t offset) {
+  return _aligned_msize(p, alignment, offset);
 }
 
-__declspec(noinline) void *_aligned_offset_malloc(size_t size, size_t alignment,
-                                                  size_t offset) {
-  const size_t total = offset + size;
-  if (total && (total - offset) != size)
+__declspec(noinline) void* _aligned_offset_realloc(void* p, size_t size,
+                                                   size_t alignment,
+                                                   size_t offset) {
+  if (!p)
+    return _aligned_offset_malloc(size, alignment, offset);
+  if (!size) {
+    _aligned_free(p);
     return nullptr;
-  void *p = _aligned_malloc(total, alignment);
-  if (p)
-    return ((u8 *)p) + offset;
+  }
+  const size_t old_size = _aligned_msize(p, alignment, offset);
+  void* n = _aligned_offset_malloc(size, alignment, offset);
+  if (n) {
+    REAL(memcpy)(n, p, Min<size_t>(size, old_size));
+    _aligned_free(p);
+  }
+  return n;
+}
 
-  return nullptr;
+__declspec(noinline) void* _aligned_offset_realloc_dbg(void* p, size_t size,
+                                                       size_t alignment,
+                                                       size_t offset,
+                                                       const char*, int) {
+  return _aligned_offset_realloc(p, size, alignment, offset);
 }
 
-__declspec(noinline) void *_aligned_offset_malloc_dbg(size_t size,
-                                                      size_t alignment,
-                                                      size_t offset) {
-  return _aligned_offset_malloc(size, alignment, offset);
+__declspec(noinline) void* _aligned_realloc(void* p, size_t size,
+                                            size_t alignment) {
+  return _aligned_offset_realloc(p, size, alignment, 0);
 }
 
-__declspec(noinline) void _aligned_free(void *p) {
-  void *b = const_cast<void *>(
-      __sanitizer_get_allocated_begin(const_cast<void *>(p)));
-  CHECK(b != nullptr && "invalid pointer");
-  free(b);
+__declspec(noinline) void* _aligned_realloc_dbg(void* p, size_t size,
+                                                size_t alignment, const char*,
+                                                int) {
+  return _aligned_realloc(p, size, alignment);
 }
 
-__declspec(noinline) void _aligned_free_dbg(void *p) { _aligned_free(p); }
+__declspec(noinline) void* _aligned_offset_recalloc(void* p, size_t nmemb,
+                                                    size_t elem_size,
+                                                    size_t alignment,
+                                                    size_t offset) {
+  const size_t size = nmemb * elem_size;
+  if (elem_size != 0 && size / elem_size != nmemb)
+    return nullptr;
+  const size_t old_size = p ? _aligned_msize(p, alignment, offset) : 0;
+  void* n = _aligned_offset_realloc(p, size, alignment, offset);
+  if (n && old_size < size)
+    REAL(memset)(((u8*)n) + old_size, 0, size - old_size);
+  return n;
+}
 
-__declspec(noinline) size_t _aligned_msize(void *p) {
-  GET_CURRENT_PC_BP_SP;
-  (void)sp;
+__declspec(noinline) void* _aligned_offset_recalloc_dbg(void* p, size_t nmemb,
+                                                        size_t elem_size,
+                                                        size_t alignment,
+                                                        size_t offset,
+                                                        const char*, int) {
+  return _aligned_offset_recalloc(p, nmemb, elem_size, alignment, offset);
+}
 
-  return asan_malloc_usable_size(p, pc, bp);
+__declspec(noinline) void* _aligned_recalloc(void* p, size_t nmemb,
+                                             size_t elem_size,
+                                             size_t alignment) {
+  return _aligned_offset_recalloc(p, nmemb, elem_size, alignment, 0);
 }
 
-__declspec(noinline) size_t _aligned_msize_dbg(void *p) {
-  return _aligned_msize(p);
+__declspec(noinline) void* _aligned_recalloc_dbg(void* p, size_t nmemb,
+                                                 size_t elem_size,
+                                                 size_t alignment, const char*,
+                                                 int) {
+  return _aligned_recalloc(p, nmemb, elem_size, alignment);
 }
 
 __declspec(noinline) void *_expand(void *memblock, size_t size) {
@@ -265,14 +315,26 @@ __declspec(dllexport) void *__cdecl __asan_recalloc(void *const ptr,
   return _recalloc(ptr, nmemb, size);
 }
 
-__declspec(dllexport) void *__cdecl __asan_aligned_malloc(
-    const size_t size, const size_t alignment) {
-  return _aligned_malloc(size, alignment);
+__declspec(dllexport) void* __cdecl __asan_aligned_offset_malloc(
+    const size_t size, const size_t alignment, const size_t offset) {
+  return _aligned_offset_malloc(size, alignment, offset);
 }
-
-__declspec(dllexport) void *__cdecl __asan_aligned_realloc(
-    void *const ptr, const size_t size, const size_t alignment) {
-  return _aligned_realloc(ptr, size, alignment);
+__declspec(dllexport) void* __cdecl __asan_aligned_offset_realloc(
+    void* const ptr, const size_t size, const size_t alignment,
+    const size_t offset) {
+  return _aligned_offset_realloc(ptr, size, alignment, offset);
+}
+__declspec(dllexport) void* __cdecl __asan_aligned_offset_recalloc(
+    void* const ptr, const size_t nmemb, const size_t size,
+    const size_t alignment, const size_t offset) {
+  return _aligned_offset_recalloc(ptr, nmemb, size, alignment, offset);
+}
+__declspec(dllexport) void __cdecl __asan_aligned_free(void* const ptr) {
+  _aligned_free(ptr);
+}
+__declspec(dllexport) size_t __cdecl __asan_aligned_msize(
+    void* const ptr, const size_t alignment, const size_t offset) {
+  return _aligned_msize(ptr, alignment, offset);
 }
 
 int _CrtDbgReport(int, const char*, int,
@@ -627,6 +689,14 @@ void ReplaceSystemMalloc() {
   TryToOverrideFunction("_aligned_offset_malloc", (uptr)_aligned_offset_malloc);
   TryToOverrideFunction("_aligned_offset_malloc_dbg",
                         (uptr)_aligned_offset_malloc_dbg);
+  TryToOverrideFunction("_aligned_offset_realloc",
+                        (uptr)_aligned_offset_realloc);
+  TryToOverrideFunction("_aligned_offset_realloc_dbg",
+                        (uptr)_aligned_offset_realloc_dbg);
+  TryToOverrideFunction("_aligned_offset_recalloc",
+                        (uptr)_aligned_offset_recalloc);
+  TryToOverrideFunction("_aligned_offset_recalloc_dbg",
+                        (uptr)_aligned_offset_recalloc_dbg);
 
   if (flags()->windows_hook_rtl_allocators) {
     ASAN_INTERCEPT_FUNC(HeapSize);
diff --git a/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
index c1f56515465a5..3c683adff2be7 100644
--- a/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win_thunk.cpp
@@ -33,15 +33,17 @@ __declspec(dllimport) void *__cdecl __asan_realloc(void *const ptr,
 __declspec(dllimport) void *__cdecl __asan_recalloc(void *const ptr,
                                                     const size_t nmemb,
                                                     const size_t size);
-
-__declspec(dllimport) void *__cdecl __asan_recalloc(void *const ptr,
-                                                    const size_t nmemb,
-                                                    const size_t size);
-__declspec(dllexport) void *__cdecl __asan_aligned_malloc(
-    const size_t size, const size_t alignment);
-
-__declspec(dllexport) void *__cdecl __asan_aligned_realloc(
-    void *const ptr, const size_t size, const size_t alignment);
+__declspec(dllimport) void* __cdecl __asan_aligned_offset_malloc(
+    const size_t size, const size_t alignment, const size_t offset);
+__declspec(dllimport) void* __cdecl __asan_aligned_offset_realloc(
+    void* const ptr, const size_t size, const size_t alignment,
+    const size_t offset);
+__declspec(dllimport) void* __cdecl __asan_aligned_offset_recalloc(
+    void* const ptr, const size_t nmemb, const size_t size,
+    const size_t alignment, const size_t offset);
+__declspec(dllimport) void __cdecl __asan_aligned_free(void* const ptr);
+__declspec(dllimport) size_t __cdecl __asan_aligned_msize(
+    void* const ptr, const size_t alignment, const size_t offset);
 
 // Avoid tailcall optimization to preserve stack frames.
 #  pragma optimize("", off)
@@ -151,67 +153,107 @@ STATIC_MALLOC_INTERFACE void *_expand_dbg(void *, size_t, int, const char *,
 }
 
 // _aligned_malloc
+STATIC_MALLOC_INTERFACE void* _aligned_malloc(const size_t size,
+                                              const size_t alignment) {
+  return __asan_aligned_offset_malloc(size, alignment, 0);
+}
+
+STATIC_MALLOC_INTERFACE void* _aligned_malloc_dbg(const size_t size,
+                                                  const size_t alignment,
+                                                  const char*, int) {
+  return __asan_aligned_offset_malloc(size, alignment, 0);
+}
 
-STATIC_MALLOC_INTERFACE void *_aligned_malloc(size_t size, size_t alignment) {
-  return __asan_aligned_malloc(size, alignment);
+STATIC_MALLOC_INTERFACE void* _aligned_offset_malloc(const size_t size,
+                                                     const size_t alignment,
+                                                     const size_t offset) {
+  return __asan_aligned_offset_malloc(size, alignment, offset);
 }
 
-STATIC_MALLOC_INTERFACE void *_aligned_malloc_dbg(size_t size,
-                                                  size_t alignment) {
-  return _aligned_malloc(size, alignment);
+STATIC_MALLOC_INTERFACE void* _aligned_offset_malloc_dbg(const size_t size,
+                                                         const size_t alignment,
+                                                         const size_t offset,
+                                                         const char*, int) {
+  return __asan_aligned_offset_malloc(size, alignment, offset);
 }
 
 // _aligned_realloc
+STATIC_MALLOC_INTERFACE void* _aligned_realloc(void* const ptr,
+                                               const size_t size,
+                                               const size_t alignment) {
+  return __asan_aligned_offset_realloc(ptr, size, alignment, 0);
+}
 
-STATIC_MALLOC_INTERFACE void *_aligned_realloc(void *p, size_t size,
-                                               size_t alignment) {
-  return __asan_aligned_realloc(p, size, alignment);
+STATIC_MALLOC_INTERFACE void* _aligned_realloc_dbg(void* const ptr,
+                                                   const size_t size,
+                                                   const size_t alignment,
+                                                   const char*, int) {
+  return __asan_aligned_offset_realloc(ptr, size, alignment, 0);
 }
 
-STATIC_MALLOC_INTERFACE void *_aligned_realloc_dbg(void *p, size_t size,
-                                                   size_t alignment) {
-  return _aligned_realloc(p, size, alignment);
+STATIC_MALLOC_INTERFACE void* _aligned_offset_realloc(void* const ptr,
+                                                      const size_t size,
+                                                      const size_t alignment,
+                                                      const size_t offset) {
+  return __asan_aligned_offset_realloc(ptr, size, alignment, offset);
 }
 
-// _aligned_offset_malloc
+STATIC_MALLOC_INTERFACE void* _aligned_offset_realloc_dbg(
+    void* const ptr, const size_t size, const size_t alignment,
+    const size_t offset, const char*, int) {
+  return __asan_aligned_offset_realloc(ptr, size, alignment, offset);
+}
 
-STATIC_MALLOC_INTERFACE void *_aligned_offset_malloc(size_t size,
-                                                     size_t alignment,
-                                                     size_t offset) {
-  const size_t total = offset + size;
-  if (total && (total - offset) != size)
-    return nullptr;
-  void *p = _aligned_malloc(total, alignment);
-  if (p)
-    return ((char *)p) + offset;
+// _aligned_recalloc
+STATIC_MALLOC_INTERFACE void* _aligned_recalloc(void* const ptr,
+                                                const size_t nmemb,
+                                                const size_t size,
+                                                const size_t alignment) {
+  return __asan_aligned_offset_recalloc(ptr, nmemb, size, alignment, 0);
+}
 
-  return nullptr;
+STATIC_MALLOC_INTERFACE void* _aligned_recalloc_dbg(void* const ptr,
+                                                    const size_t nmemb,
+                                                    const size_t size,
+                                                    const size_t alignment,
+                                                    const char*, int) {
+  return __asan_aligned_offset_recalloc(ptr, nmemb, size, alignment, 0);
 }
 
-STATIC_MALLOC_INTERFACE void *_aligned_offset_malloc_dbg(size_t size,
-                                                         size_t alignment,
-                                                         size_t offset) {
-  return _aligned_offset_malloc(size, alignment, offset);
+STATIC_MALLOC_INTERFACE void* _aligned_offset_recalloc(void* const ptr,
+                                                       const size_t nmemb,
+                                                       const size_t size,
+                                                       const size_t alignment,
+                                                       const size_t offset) {
+  return __asan_aligned_offset_recalloc(ptr, nmemb, size, alignment, offset);
 }
 
-// _aligned_free
+STATIC_MALLOC_INTERFACE void* _aligned_offset_recalloc_dbg(
+    void* const ptr, const size_t nmemb, const size_t size,
+    const size_t alignment, const size_t offset, const char*, int) {
+  return __asan_aligned_offset_recalloc(ptr, nmemb, size, alignment, offset);
+}
 
-STATIC_MALLOC_INTERFACE void _aligned_free(void *p) {
-  void *b = const_cast<void *>(
-      __sanitizer_get_allocated_begin(const_cast<void *>(p)));
-  __asan_free(b);
+// _aligned_free
+STATIC_MALLOC_INTERFACE void _aligned_free(void* const ptr) {
+  __asan_aligned_free(ptr);
 }
 
-STATIC_MALLOC_INTERFACE void _aligned_free_dbg(void *p) { _aligned_free(p); }
+STATIC_MALLOC_INTERFACE void _aligned_free_dbg(void* const ptr) {
+  __asan_aligned_free(ptr);
+}
 
 // _aligned_msize
-
-STATIC_MALLOC_INTERFACE size_t _aligned_msize(void *p) {
-  return __asan_msize(p);
+STATIC_MALLOC_INTERFACE size_t _aligned_msize(void* const ptr,
+                                              const size_t alignment,
+                                              const size_t offset) {
+  return __asan_aligned_msize(ptr, alignment, offset);
 }
 
-STATIC_MALLOC_INTERFACE size_t _aligned_msize_dbg(void *p) {
-  return __asan_msize(p);
+STATIC_MALLOC_INTERFACE size_t _aligned_msize_dbg(void* const ptr,
+                                                  const size_t alignment,
+                                                  const size_t offset) {
+  return __asan_aligned_msize(ptr, alignment, offset);
 }
 
 // We need to provide symbols for all the debug CRT functions if we decide to
diff --git a/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp b/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
index 0fea1221f27ab..91ad1d3a4d6be 100644
--- a/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/aligned_mallocs.cpp
@@ -31,18 +31,40 @@ int main(void) {
     return __LINE__;
   _aligned_free(p);
 
-  char *y = (char *)malloc(1024);
-  char *u = (char *)realloc(y, 2048);
-  u[0] = 'a';
-  _aligned_free(u);
-  u = (char *)_aligned_offset_malloc(1024, 8, 0);
-  _aligned_free(u);
+  _aligned_free(nullptr);
+
+  // Size need not be a multiple of the alignment.
+  char *c = (char *)_aligned_malloc(100, 32);
+  CHECK_ALIGNED(c, 32);
+  c[99] = 0;
+  _aligned_free(c);
+
+  // _aligned_offset_malloc aligns ptr + offset, not ptr.
+  c = (char *)_aligned_offset_malloc(100, 64, 8);
+  CHECK_ALIGNED(c + 8, 64);
+  if (_aligned_msize(c, 64, 8) != 100)
+    return __LINE__;
+  c[99] = 0;
+  c = (char *)_aligned_offset_realloc(c, 200, 64, 8);
+  CHECK_ALIGNED(c + 8, 64);
+  c[199] = 0;
+  _aligned_free(c);
+
+  // _aligned_recalloc keeps the old contents and zeroes the grown tail.
+  c = (char *)_aligned_recalloc(nullptr, 4, 4, 16);
+  CHECK_ALIGNED(c, 16);
+  c[0] = 'a';
+  c = (char *)_aligned_recalloc(c, 8, 4, 16);
+  CHECK_ALIGNED(c, 16);
+  if (c[0] != 'a' || c[31] != 0)
+    return __LINE__;
+  _aligned_free(c);
 
   char *t = (char *)_aligned_malloc(128, 8);
-  t[-153] = 'a';
+  t[128] = 'a';
+  // CHECK: AddressSanitizer: heap-buffer-overflow
+  // CHECK: WRITE of size 1
+  // CHECK: 0 bytes after 128-byte region
 
   return 0;
 }
-
-// CHECK: AddressSanitizer: access-violation on unknown address
-// CHECK: The signal is caused by a WRITE memory access.



More information about the llvm-commits mailing list