diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index 7c9a08b9083a2..2a9fee50418cc 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -65,6 +65,15 @@ static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { return internal_strnlen(s, maxlen); } +static inline uptr MaybeRealWcsnlen(const wchar_t *s, uptr maxlen) { +#if SANITIZER_INTERCEPT_WCSLEN + if (REAL(wcsnlen)) { + return REAL(wcsnlen)(s, maxlen); + } +#endif + return internal_wcsnlen(s, maxlen); +} + void SetThreadName(const char *name) { AsanThread *t = GetCurrentThread(); if (t) @@ -570,6 +579,26 @@ INTERCEPTOR(char *, strcpy, char *to, const char *from) { return REAL(strcpy)(to, from); } +INTERCEPTOR(wchar_t *, wcscpy, wchar_t *to, const wchar_t *from) { + void *ctx; + ASAN_INTERCEPTOR_ENTER(ctx, wcscpy); + if constexpr (SANITIZER_APPLE) { + if (UNLIKELY(!AsanInited())) + return REAL(wcscpy)(to, from); + } else { + if (!TryAsanInitFromRtl()) + return REAL(wcscpy)(to, from); + } + + if (flags()->replace_str) { + uptr from_size = (internal_wcslen(from) + 1) * sizeof(wchar_t); + CHECK_RANGES_OVERLAP("wcscpy", to, from_size, from, from_size); + ASAN_READ_RANGE(ctx, from, from_size); + ASAN_WRITE_RANGE(ctx, to, from_size); + } + return REAL(wcscpy)(to, from); +} + // Windows doesn't always define the strdup identifier, // and when it does it's a macro defined to either _strdup // or _strdup_dbg, _strdup_dbg ends up calling _strdup, so @@ -633,6 +662,19 @@ INTERCEPTOR(char*, strncpy, char *to, const char *from, usize size) { return REAL(strncpy)(to, from, size); } +INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *to, const wchar_t *from, usize size) { + void *ctx; + ASAN_INTERCEPTOR_ENTER(ctx, wcsncpy); + AsanInitFromRtl(); + if (flags()->replace_str) { + uptr from_size = Min(size, MaybeRealWcsnlen(from, size) + 1) * sizeof(wchar_t); + CHECK_RANGES_OVERLAP("wcsncpy", to, from_size, from, from_size); + ASAN_READ_RANGE(ctx, from, from_size); + ASAN_WRITE_RANGE(ctx, to, size * sizeof(wchar_t)); + } + return REAL(wcsncpy)(to, from, size); +} + template static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr, char **endptr, int base) @@ -808,6 +850,8 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(strcpy); ASAN_INTERCEPT_FUNC(strncat); ASAN_INTERCEPT_FUNC(strncpy); + ASAN_INTERCEPT_FUNC(wcscpy); + ASAN_INTERCEPT_FUNC(wcsncpy); ASAN_INTERCEPT_FUNC(strdup); # if ASAN_INTERCEPT___STRDUP ASAN_INTERCEPT_FUNC(__strdup); diff --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h index 3e2386eaf8092..33d4210b5815c 100644 --- a/compiler-rt/lib/asan/asan_interceptors.h +++ b/compiler-rt/lib/asan/asan_interceptors.h @@ -129,6 +129,7 @@ DECLARE_REAL(char*, strchr, const char *str, int c) DECLARE_REAL(SIZE_T, strlen, const char *s) DECLARE_REAL(char*, strncpy, char *to, const char *from, SIZE_T size) DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen) +DECLARE_REAL(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T maxlen) DECLARE_REAL(char*, strstr, const char *s1, const char *s2) # if !SANITIZER_APPLE 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 4a69b66574039..8e88f77a2536d 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(wcscat); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsncat); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcscpy); +INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsncpy); // 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/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 29987decdff45..88ecd7e16306a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -551,7 +551,7 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment, #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_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA) #define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID diff --git a/compiler-rt/test/asan/TestCases/wcscat.cpp b/compiler-rt/test/asan/TestCases/wcscat.cpp new file mode 100644 index 0000000000000..6154020788e27 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/wcscat.cpp @@ -0,0 +1,13 @@ +// REQUIRES: !windows +// RUN: %clangxx_asan -O0 -fno-builtin %s -o %t && %run %t + +#include + +int main() { + wchar_t dst[16] = L"ab"; + const wchar_t *src = L"c"; + wcscat(dst, src); + return 0; +} + + diff --git a/compiler-rt/test/asan/TestCases/wcscpy.cpp b/compiler-rt/test/asan/TestCases/wcscpy.cpp new file mode 100644 index 0000000000000..3a58f28555269 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/wcscpy.cpp @@ -0,0 +1,17 @@ +// REQUIRES: !windows +// RUN: %clangxx_asan -O0 -fno-builtin %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include + +__attribute__((noinline)) void bad_wcs(void) { + wchar_t buf[] = L"hello"; + // CHECK: wcscpy-param-overlap: memory ranges + wcscpy(buf, buf + 1); +} + +int main() { + bad_wcs(); + return 0; +} + + diff --git a/compiler-rt/test/asan/TestCases/wcsncat.cpp b/compiler-rt/test/asan/TestCases/wcsncat.cpp new file mode 100644 index 0000000000000..d260f9ce2f0f2 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/wcsncat.cpp @@ -0,0 +1,13 @@ +// REQUIRES: !windows +// RUN: %clangxx_asan -O0 -fno-builtin %s -o %t && %run %t + +#include + +int main() { + wchar_t dst[16] = L"ab"; + const wchar_t *src = L"cd"; + wcsncat(dst, src, 1); + return 0; +} + + diff --git a/compiler-rt/test/asan/TestCases/wcsncpy.cpp b/compiler-rt/test/asan/TestCases/wcsncpy.cpp new file mode 100644 index 0000000000000..70023bd1f3379 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/wcsncpy.cpp @@ -0,0 +1,13 @@ +// REQUIRES: !windows +// RUN: %clangxx_asan -O0 -fno-builtin %s -o %t && %run %t + +#include + +int main() { + wchar_t src[] = L"abc"; + wchar_t dst[4] = {0}; + wcsncpy(dst, src, 3); + return 0; +} + +