[compiler-rt] [compiler-rt][asan] _aligned_malloc/_aligned_free interception. (PR #82049)
David CARLIER via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 19 13:04:31 PST 2024
https://github.com/devnexen updated https://github.com/llvm/llvm-project/pull/82049
>From 5f7cf844731c5cd2a597fb6dcbf9a8f9028c54a8 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/3] [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 3278f072198769..7dd675a5eb63d8 100644
--- a/compiler-rt/lib/asan/asan_malloc_win.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win.cpp
@@ -142,6 +142,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.
@@ -173,8 +200,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*, ...) {
@@ -495,6 +529,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 9cc00913177eab..9dbb8dae40f45f 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 ee6ec4495e7c8f..3d507afb610ade 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 aa8ca0c8d91aecfbfb051470584290b9c82eb3e8 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/3] 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 9dbb8dae40f45f..9cc00913177eab 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 4a69b66574039c..264dc63f4c9ad8 100644
--- a/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
+++ b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
@@ -65,6 +65,10 @@ INTERCEPT_LIBRARY_FUNCTION_ASAN(strstr);
INTERCEPT_LIBRARY_FUNCTION_ASAN(strtok);
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 3d507afb610ade..47c7c2887a1c5a 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 d2d7ba0560b07398a84e4e8785e9c71aa717e380 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/3] adding few missing calls.
---
compiler-rt/lib/asan/asan_malloc_win.cpp | 63 ++++++++++++++++++-
.../asan/asan_win_static_runtime_thunk.cpp | 4 --
2 files changed, 62 insertions(+), 5 deletions(-)
diff --git a/compiler-rt/lib/asan/asan_malloc_win.cpp b/compiler-rt/lib/asan/asan_malloc_win.cpp
index 7dd675a5eb63d8..7c4ecb891df75a 100644
--- a/compiler-rt/lib/asan/asan_malloc_win.cpp
+++ b/compiler-rt/lib/asan/asan_malloc_win.cpp
@@ -147,6 +147,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;
@@ -160,7 +164,52 @@ __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(size + offset, 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;
@@ -169,6 +218,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.
@@ -531,8 +584,16 @@ 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 264dc63f4c9ad8..4a69b66574039c 100644
--- a/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
+++ b/compiler-rt/lib/asan/asan_win_static_runtime_thunk.cpp
@@ -65,10 +65,6 @@ INTERCEPT_LIBRARY_FUNCTION_ASAN(strstr);
INTERCEPT_LIBRARY_FUNCTION_ASAN(strtok);
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,
More information about the llvm-commits
mailing list