[compiler-rt] [asan][Windows] Add additional wcs* interceptors (PR #66128)
nicole mazzuca via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 18 09:06:13 PDT 2023
https://github.com/strega-nil-ms updated https://github.com/llvm/llvm-project/pull/66128
>From 8d5b48eea08325ea445bc1220c97a2e139317bf7 Mon Sep 17 00:00:00 2001
From: Nicole Mazzuca <nicole at strega-nil.co>
Date: Tue, 12 Sep 2023 11:59:23 -0700
Subject: [PATCH 1/2] Add moar wcs* interceptions
wcs[n]cat, wcs[n]cmp, wcs[n]cpy, and wcschr
wcs[n]cat already existed, but only on POSIX
---
compiler-rt/lib/asan/asan_win_dll_thunk.cpp | 7 +
.../lib/interception/interception_win.cpp | 91 +++++--
.../sanitizer_common_interceptors.inc | 99 ++++++++
.../sanitizer_platform_interceptors.h | 5 +-
.../TestCases/Windows/replaced_functions.c | 237 ++++++++++++++++++
5 files changed, 418 insertions(+), 21 deletions(-)
create mode 100644 compiler-rt/test/asan/TestCases/Windows/replaced_functions.c
diff --git a/compiler-rt/lib/asan/asan_win_dll_thunk.cpp b/compiler-rt/lib/asan/asan_win_dll_thunk.cpp
index 0fa636bec0d001a..f122fb3145e19f8 100644
--- a/compiler-rt/lib/asan/asan_win_dll_thunk.cpp
+++ b/compiler-rt/lib/asan/asan_win_dll_thunk.cpp
@@ -93,7 +93,14 @@ INTERCEPT_LIBRARY_FUNCTION(strstr);
INTERCEPT_LIBRARY_FUNCTION(strtok);
INTERCEPT_LIBRARY_FUNCTION(strtol);
INTERCEPT_LIBRARY_FUNCTION(strtoll);
+INTERCEPT_LIBRARY_FUNCTION(wcscat);
+INTERCEPT_LIBRARY_FUNCTION(wcschr);
+INTERCEPT_LIBRARY_FUNCTION(wcscmp);
+INTERCEPT_LIBRARY_FUNCTION(wcscpy);
INTERCEPT_LIBRARY_FUNCTION(wcslen);
+INTERCEPT_LIBRARY_FUNCTION(wcsncat);
+INTERCEPT_LIBRARY_FUNCTION(wcsncmp);
+INTERCEPT_LIBRARY_FUNCTION(wcsncpy);
INTERCEPT_LIBRARY_FUNCTION(wcsnlen);
# if defined(_MSC_VER) && !defined(__clang__)
diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp
index b2ba40902347f46..2e3ca6adfbfa3d1 100644
--- a/compiler-rt/lib/interception/interception_win.cpp
+++ b/compiler-rt/lib/interception/interception_win.cpp
@@ -525,15 +525,21 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
switch (*(u16*)(address)) {
case 0x018A: // 8A 01 : mov al, byte ptr [ecx]
case 0xFF8B: // 8B FF : mov edi, edi
+ case 0xDC8B: // 8B DC : mov ebx, esp
case 0xEC8B: // 8B EC : mov ebp, esp
case 0xc889: // 89 C8 : mov eax, ecx
case 0xE589: // 89 E5 : mov ebp, esp
case 0xC18B: // 8B C1 : mov eax, ecx
+ case 0xFF33: // 33 FF : xor edi, edi
case 0xC033: // 33 C0 : xor eax, eax
case 0xC933: // 33 C9 : xor ecx, ecx
case 0xD233: // 33 D2 : xor edx, edx
return 2;
+ case 0xEC83: // 83 EC XX : sub esp, XX
+ case 0xE483: // 83 E4 XX : and esp, XX
+ return 3;
+
// Cannot overwrite control-instruction. Return 0 to indicate failure.
case 0x25FF: // FF 25 XX XX XX XX : jmp [XXXXXXXX]
return 0;
@@ -577,6 +583,10 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
case 0x018a: // mov al, byte ptr [rcx]
return 2;
+ case 0xE483: // 83 E4 XX : and esp, XX
+ case 0xC1F6: // F6 C1 XX : test cl, XX
+ return 3;
+
case 0x058B: // 8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]
if (rel_offset)
*rel_offset = 2;
@@ -584,37 +594,72 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
}
switch (0x00FFFFFF & *(u32*)address) {
- case 0xe58948: // 48 8b c4 : mov rbp, rsp
- case 0xc18b48: // 48 8b c1 : mov rax, rcx
- case 0xc48b48: // 48 8b c4 : mov rax, rsp
- case 0xd9f748: // 48 f7 d9 : neg rcx
- case 0xd12b48: // 48 2b d1 : sub rdx, rcx
- case 0x07c1f6: // f6 c1 07 : test cl, 0x7
- case 0xc98548: // 48 85 C9 : test rcx, rcx
- case 0xd28548: // 48 85 d2 : test rdx, rdx
- case 0xc0854d: // 4d 85 c0 : test r8, r8
case 0xc2b60f: // 0f b6 c2 : movzx eax, dl
- case 0xc03345: // 45 33 c0 : xor r8d, r8d
- case 0xc93345: // 45 33 c9 : xor r9d, r9d
- case 0xdb3345: // 45 33 DB : xor r11d, r11d
- case 0xd98b4c: // 4c 8b d9 : mov r11, rcx
- case 0xd28b4c: // 4c 8b d2 : mov r10, rdx
- case 0xc98b4c: // 4C 8B C9 : mov r9, rcx
- case 0xc18b4c: // 4C 8B C1 : mov r8, rcx
case 0xd2b60f: // 0f b6 d2 : movzx edx, dl
- case 0xca2b48: // 48 2b ca : sub rcx, rdx
- case 0x10b70f: // 0f b7 10 : movzx edx, WORD PTR [rax]
+ case 0x01b70f: // 0f b7 01 : movzx eax, word ptr [rcx]
+ case 0x02b70f: // 0f b7 02 : movzx eax, word ptr [rdx]
+ case 0x10b70f: // 0f b7 10 : movzx edx, word ptr [rax]
+ case 0xc2b70f: // 0f b7 c2 : movzx eax, dx
case 0xc00b4d: // 3d 0b c0 : or r8, r8
case 0xc08b41: // 41 8b c0 : mov eax, r8d
+ case 0xc18b41: // 41 8b c1 : mov eax, r9d
+ case 0xc28b41: // 41 8b c2 : mov eax, r10d
+ case 0xc38b41: // 41 8b c3 : mov eax, r11d
+ case 0xc48b41: // 41 8b c4 : mov eax, r12d
+ case 0xc03345: // 45 33 c0 : xor r8d, r8d
+ case 0xc93345: // 45 33 c9 : xor r9d, r9d
+ case 0xdb3345: // 45 33 db : xor r11d, r11d
+ case 0xca2b48: // 48 2b ca : sub rcx, rdx
+ case 0xd12b48: // 48 2b d1 : sub rdx, rcx
+ case 0xca3b48: // 48 3b ca : cmp rcx, rdx
+ case 0xc08548: // 48 85 c0 : test rax, rax
+ case 0xc98548: // 48 85 c9 : test rcx, rcx
+ case 0xd28548: // 48 85 d2 : test rdx, rdx
+ case 0xdb8548: // 48 85 db : test rbx, rbx
+ case 0xe48548: // 48 85 e4 : test rsp, rsp
+ case 0xed8548: // 48 85 ed : test rbp, rbp
+ case 0xe58948: // 48 89 e5 : mov rbp, rsp
+ case 0xc18b48: // 48 8b c1 : mov rax, rcx
+ case 0xc48b48: // 48 8b c4 : mov rax, rsp
case 0xd18b48: // 48 8b d1 : mov rdx, rcx
- case 0xdc8b4c: // 4c 8b dc : mov r11, rsp
+ case 0xd9f748: // 48 f7 d9 : neg rcx
+ case 0xc0ff48: // 48 ff c0 : inc rax
+ case 0xc1ff48: // 48 ff c1 : inc rcx
+ case 0xc2ff48: // 48 ff c2 : inc rdx
+ case 0xc3ff48: // 48 ff c3 : inc rbx
+ case 0xc6ff48: // 48 ff c6 : inc rsi
+ case 0xc7ff48: // 48 ff c7 : inc rdi
+ case 0xc0ff49: // 49 ff c0 : inc r8
+ case 0xc1ff49: // 49 ff c1 : inc r9
+ case 0xc2ff49: // 49 ff c2 : inc r10
+ case 0xc3ff49: // 49 ff c3 : inc r11
+ case 0xc4ff49: // 49 ff c4 : inc r12
+ case 0xc5ff49: // 49 ff c5 : inc r13
+ case 0xc6ff49: // 49 ff c6 : inc r14
+ case 0xc7ff49: // 49 ff c7 : inc r15
+ case 0xc22b4c: // 4c 2b c2 : sub r8, rdx
+ case 0xc18b4c: // 4c 8b c1 : mov r8, rcx
+ case 0xc98b4c: // 4c 8b c9 : mov r9, rcx
case 0xd18b4c: // 4c 8b d1 : mov r10, rcx
- case 0xE0E483: // 83 E4 E0 : and esp, 0xFFFFFFE0
+ case 0xd28b4c: // 4c 8b d2 : mov r10, rdx
+ case 0xd98b4c: // 4c 8b d9 : mov r11, rcx
+ case 0xdc8b4c: // 4c 8b dc : mov r11, rsp
+ case 0xc0854d: // 4d 85 c0 : test r8, r8
+ case 0xc9854d: // 4d 85 c9 : test r9, r9
+ case 0xd2854d: // 4d 85 d2 : test r10, r10
+ case 0xdb854d: // 4d 85 db : test r11, r11
+ case 0xe4854d: // 4d 85 e4 : test r12, r12
+ case 0xed854d: // 4d 85 ed : test r13, r13
+ case 0xf6854d: // 4d 85 f6 : test r14, r14
+ case 0xff854d: // 4d 85 ff : test r15, r15
return 3;
case 0xec8348: // 48 83 ec XX : sub rsp, XX
case 0xf88349: // 49 83 f8 XX : cmp r8, XX
case 0x588948: // 48 89 58 XX : mov QWORD PTR[rax + XX], rbx
+ case 0x245489: // 89 54 24 XX : mov DWORD PTR[rsp + XX], edx
+ case 0x398366: // 66 83 39 XX : cmp DWORD PTR [rcx], XX
+ case 0x428d44: // 44 8d 42 XX : lea r8d , [rdx + XX]
return 4;
case 0xec8148: // 48 81 EC XX XX XX XX : sub rsp, XXXXXXXX
@@ -636,6 +681,8 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
}
switch (*(u32*)(address)) {
+ case 0x01b70f44: // 44 0f b7 01 : movzx r8d, WORD PTR [rcx]
+ return 4;
case 0x24448b48: // 48 8b 44 24 XX : mov rax, QWORD ptr [rsp + XX]
case 0x246c8948: // 48 89 6C 24 XX : mov QWORD ptr [rsp + XX], rbp
case 0x245c8948: // 48 89 5c 24 XX : mov QWORD PTR [rsp + XX], rbx
@@ -645,6 +692,10 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
case 0x24548948: // 48 89 54 24 XX : mov QWORD PTR [rsp + XX], rdx
case 0x244c894c: // 4c 89 4c 24 XX : mov QWORD PTR [rsp + XX], r9
case 0x2444894c: // 4c 89 44 24 XX : mov QWORD PTR [rsp + XX], r8
+ case 0x244c8944: // 44 89 4c 24 XX mov DWORD PTR [rsp + XX], r9d
+ case 0x24448944: // 44 89 44 24 XX mov DWORD PTR [rsp + XX], r8d
+ case 0x24548966: // 66 89 54 24 XX : mov [rsp + XX], dx
+ case 0x246c8d48: // 48 8d 6c 24 XX : lea rbp, [rsp + XX]
return 5;
case 0x24648348: // 48 83 64 24 XX : and QWORD PTR [rsp + XX], YY
return 6;
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 0e563fa12022a3e..87192ed2d5aa227 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -449,6 +449,9 @@ INTERCEPTOR(char*, textdomain, const char *domainname) {
static inline int CharCmpX(unsigned char c1, unsigned char c2) {
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
}
+static inline int WCharCmpX(wchar_t c1, wchar_t c2) {
+ return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
+}
DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, uptr called_pc,
const char *s1, const char *s2, int result)
@@ -7090,6 +7093,99 @@ INTERCEPTOR(wchar_t *, wcsdup, wchar_t *s) {
#define INIT_WCSDUP
#endif
+#if SANITIZER_INTERCEPT_WCSCPY
+INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dst, const wchar_t *src) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcscpy, dst, src);
+ SIZE_T src_len = internal_wcslen(src);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(wchar_t) * (src_len + 1));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(wchar_t) * (src_len + 1));
+ wchar_t *result = internal_wcscpy(dst, src);
+ return result;
+}
+INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dst, const wchar_t *src, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcsncpy, dst, src, size);
+ SIZE_T src_len = internal_wcsnlen(src, size);
+ if (src_len != size)
+ ++src_len; // account for the nul terminator
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(wchar_t) * src_len);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(wchar_t) * src_len);
+ wchar_t *result = internal_wcsncpy(dst, src, size);
+ return result;
+}
+
+#define INIT_WCSCPY \
+ COMMON_INTERCEPT_FUNCTION(wcscpy); \
+ COMMON_INTERCEPT_FUNCTION(wcsncpy);
+#else
+#define INIT_WCSCPY
+#endif
+
+#if SANITIZER_INTERCEPT_WCSCMP
+INTERCEPTOR(int, wcscmp, const wchar_t *s1, const wchar_t *s2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcscmp, s1, s2);
+ wchar_t c1, c2;
+ uptr i;
+ for (i = 0;; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if (c1 != c2 || c1 == '\0') break;
+ }
+ if (common_flags()->intercept_strcmp) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, sizeof(wchar_t) * (i + 1));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, sizeof(wchar_t) * (i + 1));
+ }
+ int result = WCharCmpX(c1, c2);
+ return result;
+}
+INTERCEPTOR(int, wcsncmp, wchar_t *s1, const wchar_t *s2, SIZE_T size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcsncmp, s1, s2, size);
+ wchar_t c1, c2;
+ uptr i;
+ for (i = 0; i < size; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if (c1 != c2 || c1 == '\0') break;
+ }
+ uptr i1 = i;
+ uptr i2 = i;
+ if (common_flags()->strict_string_checks) {
+ for (; i1 < size && s1[i1]; i1++) {}
+ for (; i2 < size && s2[i2]; i2++) {}
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, sizeof(wchar_t) * Min(i1 + 1, size));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, sizeof(wchar_t) * Min(i2 + 1, size));
+ int result = WCharCmpX(c1, c2);
+ return result;
+}
+
+#define INIT_WCSCMP \
+ COMMON_INTERCEPT_FUNCTION(wcscmp); \
+ COMMON_INTERCEPT_FUNCTION(wcsncmp);
+#else
+#define INIT_WCSCMP
+#endif
+
+#if SANITIZER_INTERCEPT_WCSCHR
+INTERCEPTOR(wchar_t*, wcschr, const wchar_t *s, wchar_t c) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcschr, s, c);
+ wchar_t *result = REAL(wcschr)(s, c);
+ if (common_flags()->intercept_strchr) {
+ SIZE_T read_size = (result ? result - s : internal_wcslen(s)) + 1;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(*s) * read_size);
+ }
+ return result;
+}
+
+#define INIT_WCSCHR COMMON_INTERCEPT_FUNCTION(wcschr)
+#else
+#define INIT_WCSCHR
+#endif
+
#if SANITIZER_INTERCEPT_STRXFRM
static SIZE_T RealStrLen(const char *str) { return internal_strlen(str); }
@@ -10474,6 +10570,9 @@ static void InitializeCommonInterceptors() {
INIT_WCSLEN;
INIT_WCSCAT;
INIT_WCSDUP;
+ INIT_WCSCHR;
+ INIT_WCSCMP;
+ INIT_WCSCPY;
INIT_WCSXFRM;
INIT___WCSXFRM_L;
INIT_ACCT;
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 8c7c00de6d1292f..ef5d14d4e16f967 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -496,8 +496,11 @@
#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD)
#define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_WCSLEN 1
-#define SANITIZER_INTERCEPT_WCSCAT SI_POSIX
+#define SANITIZER_INTERCEPT_WCSCAT (SI_POSIX || SI_WINDOWS)
#define SANITIZER_INTERCEPT_WCSDUP SI_POSIX
+#define SANITIZER_INTERCEPT_WCSCPY SI_WINDOWS
+#define SANITIZER_INTERCEPT_WCSCMP SI_WINDOWS
+#define SANITIZER_INTERCEPT_WCSCHR SI_WINDOWS
#define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA)
#define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID
diff --git a/compiler-rt/test/asan/TestCases/Windows/replaced_functions.c b/compiler-rt/test/asan/TestCases/Windows/replaced_functions.c
new file mode 100644
index 000000000000000..609da83690b3f92
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/Windows/replaced_functions.c
@@ -0,0 +1,237 @@
+// RUN: %clang_cl_asan /Od %s /Fe%t
+
+#define _CRT_SECURE_NO_WARNINGS
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <malloc.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+// the size parameter is the size of the src buffer in bytes
+// (dst has size 2 * size, for strcat reasons)
+// the last two bytes are 0 (for str/wcs functions)
+// they have distinct first bytes
+// dst will be free'd if --fail is passed
+typedef int test_function_t(void *, const void *, size_t);
+
+#if __clang__
+# define DECLARE_WRAPPED(name) typeof(name) __asan_wrap_##name;
+#else
+// typeof is only supported in MSVC as of 17.7, with `-std:clatest`,
+// and it doesn't seem to be possible to pass an option _only_ to cl
+# define DECLARE_WRAPPED(name) int __asan_wrap_##name();
+#endif
+
+#define TEST_FUNCTION_DECL(name) \
+ __declspec(dllexport) int test_##name(void *dst, const void *src, size_t size)
+#define TEST_WRAPPED_FUNCTION_DECL(name) \
+ DECLARE_WRAPPED(name) \
+ __declspec(dllexport) int test_wrap_##name(void *dst, const void *src, \
+ size_t size)
+
+#define TEST_FUNCTION(name, ...) \
+ TEST_FUNCTION_DECL(name) { return 0 != name(__VA_ARGS__); } \
+ TEST_WRAPPED_FUNCTION_DECL(name) { \
+ return 0 != __asan_wrap_##name(__VA_ARGS__); \
+ }
+
+#define TEST_NOT_FUNCTION(name, ...) \
+ TEST_FUNCTION_DECL(name) { return 0 == name(__VA_ARGS__); } \
+ TEST_WRAPPED_FUNCTION_DECL(name) { \
+ return 0 == __asan_wrap_##name(__VA_ARGS__); \
+ }
+
+// RUN: %run %t --success memset 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped memset 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail memset 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped memset 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(memset, dst, *(const char *)src, size)
+// RUN: %run %t --success memmove 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped memmove 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail memmove 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped memmove 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(memmove, dst, src, size)
+// RUN: %run %t --success memcpy 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped memcpy 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail memcpy 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped memcpy 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(memcpy, dst, src, size)
+// RUN: %run %t --success memcmp 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped memcmp 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail memcmp 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped memcmp 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(memcmp, dst, src, size)
+// RUN: %run %t --success memchr 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped memchr 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail memchr 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped memchr 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_NOT_FUNCTION(memchr, dst, *(const char *)src, size)
+
+// RUN: %run %t --success strlen 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped strlen 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail strlen 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped strlen 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(strlen, dst)
+// RUN: %run %t --success strnlen 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped strnlen 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail strnlen 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped strnlen 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(strnlen, dst, size)
+// RUN: %run %t --success strcpy 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped strcpy 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail strcpy 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped strcpy 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(strcpy, dst, src)
+// RUN: %run %t --success strncpy 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped strncpy 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail strncpy 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped strncpy 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(strncpy, dst, src, size)
+// RUN: %run %t --success strcat 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped strcat 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail strcat 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped strcat 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(strcat, dst, src)
+// RUN: %run %t --success strncat 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped strncat 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail strncat 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped strncat 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(strncat, dst, src, size)
+// RUN: %run %t --success strcmp 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped strcmp 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail strcmp 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped strcmp 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(strcmp, dst, src)
+// RUN: %run %t --success strncmp 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped strncmp 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail strncmp 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped strncmp 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(strncmp, dst, src, size)
+// RUN: %run %t --success strchr 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped strchr 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail strchr 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped strchr 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_NOT_FUNCTION(strchr, dst, *(const char *)src)
+
+// RUN: %run %t --success wcslen 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped wcslen 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail wcslen 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped wcslen 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(wcslen, dst)
+// RUN: %run %t --success wcsnlen 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped wcsnlen 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail wcsnlen 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped wcsnlen 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(wcsnlen, dst, size)
+// RUN: %run %t --success wcscpy 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped wcscpy 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail wcscpy 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped wcscpy 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(wcscpy, dst, src)
+// RUN: %run %t --success wcsncpy 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped wcsncpy 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail wcsncpy 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped wcsncpy 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(wcsncpy, dst, src, size / 2)
+// RUN: %run %t --success wcscat 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped wcscat 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail wcscat 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped wcscat 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(wcscat, dst, src)
+// RUN: %run %t --success wcsncat 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped wcsncat 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail wcsncat 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped wcsncat 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(wcsncat, dst, src, size / 2)
+// RUN: %run %t --success wcscmp 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped wcscmp 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail wcscmp 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped wcscmp 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(wcscmp, dst, src)
+// note: clang does not actually emit a call to wcsncmp, for some reason
+// RUN: %run %t --success --wrapped wcsncmp 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail --wrapped wcsncmp 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_FUNCTION(wcsncmp, dst, src, size / 2)
+// RUN: %run %t --success wcschr 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: %run %t --success --wrapped wcschr 2>&1 | FileCheck %s --check-prefix=CHECK-SUCCESS
+// RUN: not %run %t --fail wcschr 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+// RUN: not %run %t --fail --wrapped wcschr 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL
+TEST_NOT_FUNCTION(wcschr, dst, *(const wchar_t *)src)
+
+void help(const char *progname) {
+ fprintf(stderr, "Usage: %s (--fail|--success) [--wrapped] <intrinsic>\n",
+ progname);
+ exit(1);
+}
+
+enum SuccessOrFail {
+ SOF_None,
+ SOF_Succeed,
+ SOF_Fail,
+};
+
+int main(int argc, char *argv[]) {
+ if (argc < 3 || argc > 4) {
+ help(argv[0]);
+ }
+
+ const size_t size = 8;
+
+ void *src = malloc(size);
+ memset(src, 1, size);
+ ((wchar_t *)src)[size / 2 - 1] = L'\0';
+
+ void *dst = malloc(size * 2);
+ memset(dst, 2, size);
+ ((wchar_t *)dst)[size / 2 - 1] = L'\0';
+
+ bool wrapped = false;
+ enum SuccessOrFail succeed = SOF_None;
+ const char *function_name = 0;
+ for (int i = 1; i < argc; ++i) {
+ if (strcmp(argv[i], "--success") == 0) {
+ succeed = SOF_Succeed;
+ } else if (strcmp(argv[i], "--fail") == 0) {
+ succeed = SOF_Fail;
+ } else if (strcmp(argv[i], "--wrapped") == 0) {
+ wrapped = true;
+ } else {
+ function_name = argv[i];
+ }
+ }
+
+ if (!function_name || succeed == SOF_None) {
+ help(argv[0]);
+ } else if (succeed == SOF_Fail) {
+ free(
+ dst); // free dst, so that the function _should_ fail if ASan is correctly implemented
+ }
+
+ test_function_t *test_function = 0;
+ char buffer[32];
+ if (!wrapped) {
+ strcpy(buffer, "test_");
+ } else {
+ strcpy(buffer, "test_wrap_");
+ }
+
+ // CHECK-FAIL: ERROR: AddressSanitizer: heap-use-after-free
+ // CHECK-SUCCESS: pass
+ // CHECK-SUCCESS-NOT: ERROR: AddressSanitizer: heap-use-after-free
+
+ if (strncat(buffer, function_name, 32)) {
+ test_function = (test_function_t *)GetProcAddress(0, buffer);
+ }
+
+ if (!test_function) {
+ fprintf(stderr, "Unknown test: %s\n", argv[2]);
+ return 1;
+ }
+
+ return !(test_function(dst, src, size) && printf("pass\n"));
+}
>From 04b4c600c3736967f6e65e55350ef5428777c027 Mon Sep 17 00:00:00 2001
From: nicole mazzuca <83086508+strega-nil-ms at users.noreply.github.com>
Date: Wed, 13 Sep 2023 08:34:27 -0800
Subject: [PATCH 2/2] Allow test to run on mingw-w64
Co-authored-by: alvinhochun <alvin at alvinhc.com>
---
compiler-rt/test/asan/TestCases/Windows/replaced_functions.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compiler-rt/test/asan/TestCases/Windows/replaced_functions.c b/compiler-rt/test/asan/TestCases/Windows/replaced_functions.c
index 609da83690b3f92..545604f0c97613b 100644
--- a/compiler-rt/test/asan/TestCases/Windows/replaced_functions.c
+++ b/compiler-rt/test/asan/TestCases/Windows/replaced_functions.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cl_asan /Od %s /Fe%t
+// RUN: %clang_cl_asan %Od %s %Fe%t
#define _CRT_SECURE_NO_WARNINGS
#define NOMINMAX
More information about the llvm-commits
mailing list