diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_format.inc @@ -340,11 +340,19 @@ size = 0; } COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size); - // For %ms/%mc, write the allocated output buffer as well. + // For %mc/%mC/%ms/%mS, write the allocated output buffer as well. if (dir.allocate) { - char *buf = *(char **)argp; - if (buf) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, internal_strlen(buf) + 1); + if (char *buf = *(char **)argp) { + if (dir.convSpecifier == 'c') + size = 1; + else if (dir.convSpecifier == 'C') + size = sizeof(wchar_t); + else if (dir.convSpecifier == 's') + size = internal_strlen(buf) + 1; + else + size = (internal_wcslen((wchar_t *)buf) + 1) * sizeof(wchar_t); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, size); + } } } } diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_format_interceptor_test.cpp @@ -9,14 +9,15 @@ // Tests for *scanf interceptors implementation in sanitizer_common. // //===----------------------------------------------------------------------===// +#include #include #include +#include "gtest/gtest.h" #include "interception/interception.h" -#include "sanitizer_test_utils.h" -#include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_common.h" -#include "gtest/gtest.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_test_utils.h" using namespace __sanitizer; @@ -206,21 +207,30 @@ TEST(SanitizerCommonInterceptors, ScanfAllocate) { const char *buf = "123456"; + const wchar_t *wbuf = L"123"; // Can not use testScanf() because this case needs a valid pointer to a string // in the scanf argument. - { - std::vector scanf_sizes; - testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%ms", &buf); - verifyFormatResults("%ms", 2, scanf_sizes, - {P, (unsigned)(strlen(buf) + 1)}); - } - { std::vector scanf_sizes; testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mc", &buf); - verifyFormatResults("%mc", 2, scanf_sizes, - {P, (unsigned)(strlen(buf) + 1)}); + verifyFormatResults("%mc", 2, scanf_sizes, {P, 1u}); + } + { + std::vector scanf_sizes; + testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mC", &wbuf); + verifyFormatResults("%mC", 2, scanf_sizes, {P, (unsigned)sizeof(wchar_t)}); + } + { + std::vector scanf_sizes; + testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%ms", &buf); + verifyFormatResults("%ms", 2, scanf_sizes, {P, unsigned(strlen(buf) + 1)}); + } + { + std::vector scanf_sizes; + testScanf3((void *)&scanf_sizes, 2, /*allowGnuMalloc=*/false, "%mS", &wbuf); + verifyFormatResults("%mS", 2, scanf_sizes, + {P, unsigned((wcslen(wbuf) + 1) * sizeof(wchar_t))}); } }