Index: lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- lib/sanitizer_common/sanitizer_common_interceptors.inc +++ lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -6529,6 +6529,41 @@ #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, + sizeof(wchar_t) * (REAL(wcslen)(src) + 1)); + + SIZE_T res = REAL(wcsxfrm)(dest, src, len); + if (res < len) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, sizeof(wchar_t) * (res + 1)); + + 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, + sizeof(wchar_t) * (REAL(wcslen)(src) + 1)); + + SIZE_T res = REAL(wcsxfrm_l)(dest, src, len, locale); + if (res < len) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, sizeof(wchar_t) * (res + 1)); + + 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; @@ -7275,6 +7310,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 =================================================================== --- test/msan/wcsxfrm.cc +++ test/msan/wcsxfrm.cc @@ -0,0 +1,30 @@ +// RUN: %clangxx_msan -O0 -g %s -o %t && not %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)); + + q[0] = 'A'; + q[1] = '\x00'; + __msan_poison(&q, sizeof(q)); + wcsxfrm(NULL, q, 0); + + // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value + // CHECK: in main {{.*}}wcsxfrm.cc:25 + return 0; +} Index: test/sanitizer_common/TestCases/Posix/wcsxfrm.c =================================================================== --- test/sanitizer_common/TestCases/Posix/wcsxfrm.c +++ test/sanitizer_common/TestCases/Posix/wcsxfrm.c @@ -0,0 +1,19 @@ +// 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; +}