Index: lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- lib/sanitizer_common/sanitizer_common_interceptors.inc +++ lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -6522,6 +6522,43 @@ #define INIT_WCSCAT #endif +#if SANITIZER_INTERCEPT_WCSXFRM +INTERCEPTOR(SIZE_T, wcsxfrm, wchar_t *dest, const wchar_t *src, SIZE_T len) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsxfrm, dest, src, len); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(wcslen)(src) + 1); + + SIZE_T res = REAL(wcsxfrm)(dest, src, len); + if (dest) { + SIZE_T write_cnt = Min(len, res + 1); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, sizeof(wchar_t) * write_cnt); + } + + return res; +} + +INTERCEPTOR(SIZE_T, wcsxfrm_l, wchar_t *dest, const wchar_t *src, SIZE_T len, + void *locale) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcsxfrm_l, dest, src, len, locale); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(wcslen)(src) + 1); + + SIZE_T res = REAL(wcsxfrm_l)(dest, src, len, locale); + if (dest) { + SIZE_T write_cnt = Min(len, res + 1); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, sizeof(wchar_t) * write_cnt); + } + + return res; +} + +#define INIT_WCSXFRM \ + COMMON_INTERCEPT_FUNCTION(wcsxfrm); \ + COMMON_INTERCEPT_FUNCTION(wcsxfrm_l); +#else +#define INIT_WCSXFRM +#endif + #if SANITIZER_INTERCEPT_ACCT INTERCEPTOR(int, acct, const char *file) { void *ctx; @@ -7238,6 +7275,7 @@ INIT_GETLOADAVG; INIT_WCSLEN; INIT_WCSCAT; + INIT_WCSXFRM; INIT_ACCT; INIT_USER_FROM_UID; INIT_UID_FROM_USER; Index: lib/sanitizer_common/sanitizer_platform_interceptors.h =================================================================== --- lib/sanitizer_common/sanitizer_platform_interceptors.h +++ lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -246,6 +246,7 @@ #define SANITIZER_INTERCEPT_MBSNRTOWCS \ (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_WCSTOMBS SI_POSIX +#define SANITIZER_INTERCEPT_WCSXFRM SI_POSIX #define SANITIZER_INTERCEPT_WCSNRTOMBS \ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_WCRTOMB \ Index: test/msan/wcsxfrm.cc =================================================================== --- /dev/null +++ test/msan/wcsxfrm.cc @@ -0,0 +1,22 @@ +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t + +#include +#include +#include +#include +#include + +int main(void) { + wchar_t q[10]; + size_t n = wcsxfrm(q, L"abcdef", sizeof(q) / sizeof(wchar_t)); + assert(n < sizeof(q)); + __msan_check_mem_is_initialized(q, (n + 1) * sizeof(wchar_t)); + + locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); + + __msan_poison(&q, sizeof(q)); + n = wcsxfrm_l(q, L"qwerty", sizeof(q) / sizeof(wchar_t), loc); + assert(n < sizeof(q)); + __msan_check_mem_is_initialized(q, (n + 1) * sizeof(wchar_t)); + return 0; +} Index: test/sanitizer_common/TestCases/Posix/wcsxfrm.c =================================================================== --- /dev/null +++ test/sanitizer_common/TestCases/Posix/wcsxfrm.c @@ -0,0 +1,20 @@ +// RUN: %clang -O0 %s -o %t && %run %t + +#include +#include +#include + +int main(int argc, char **argv) { + wchar_t q[10]; + size_t n = wcsxfrm(q, L"abcdef", sizeof(q) / sizeof(wchar_t)); + assert(n < sizeof(q)); + + wchar_t q2[10]; + locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); + n = wcsxfrm_l(q2, L"qwerty", sizeof(q) / sizeof(wchar_t), loc); + assert(n < sizeof(q2)); + + freelocale(loc); + return 0; + +}