diff --git a/compiler-rt/lib/msan/tests/msan_test.cc b/compiler-rt/lib/msan/tests/msan_test.cc index b49df529d1fe..fe75d3597c87 100644 --- a/compiler-rt/lib/msan/tests/msan_test.cc +++ b/compiler-rt/lib/msan/tests/msan_test.cc @@ -1210,6 +1210,19 @@ TEST(MemorySanitizer, asprintf) { // NOLINT free(pbuf); } +TEST(MemorySanitizer, mbstowcs) { + const char *x = "abc"; + wchar_t buff[10]; + int res = mbstowcs(buff, x, 2); + EXPECT_EQ(2, res); + EXPECT_EQ(L'a', buff[0]); + EXPECT_EQ(L'b', buff[1]); + EXPECT_POISONED(buff[2]); + res = mbstowcs(buff, x, 10); + EXPECT_EQ(3, res); + EXPECT_NOT_POISONED(buff[3]); +} + TEST(MemorySanitizer, wcstombs) { const wchar_t *x = L"abc"; char buff[10]; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 329ff2c3cce5..d9c6fc243ba9 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -1540,8 +1540,10 @@ INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len); SIZE_T res = REAL(mbstowcs)(dest, src, len); - if (res != (SIZE_T) - 1 && dest) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, (res + 1) * sizeof(wchar_t)); + if (res != (SIZE_T)-1 && dest) { + SIZE_T write_cnt = res + (res < len); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); + } return res; } @@ -1549,12 +1551,13 @@ INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len, void *ps) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, mbsrtowcs, dest, src, len, ps); - if (src) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); - } + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps); - if (res != (SIZE_T) - 1 && dest) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, (res + 1) * sizeof(wchar_t)); + if (res != (SIZE_T)-1 && dest) { + // Terminating '\0' is not printed iff *src is cleared. + SIZE_T write_cnt = res + !(*src); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); + } return res; } @@ -1570,13 +1573,16 @@ INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms, SIZE_T len, void *ps) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, mbsnrtowcs, dest, src, nms, len, ps); - if (src) { + if (nms) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms); COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); - if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms); } SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps); - if (res != (SIZE_T) - 1 && dest) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, (res + 1) * sizeof(wchar_t)); + if (res != (SIZE_T)-1 && dest && nms) { + // Terminating '\0' is not printed iff *src is cleared. + SIZE_T write_cnt = res + !(*src); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t)); + } return res; } @@ -1590,8 +1596,10 @@ INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len); SIZE_T res = REAL(wcstombs)(dest, src, len); - if (res != (SIZE_T) - 1 && dest) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res + 1); + if (res != (SIZE_T)-1 && dest) { + SIZE_T write_cnt = res + (res < len); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + } return res; } @@ -1599,12 +1607,13 @@ INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len, void *ps) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, wcsrtombs, dest, src, len, ps); - if (src) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); - } + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps); - if (res != (SIZE_T) - 1 && dest) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res + 1); + if (res != (SIZE_T)-1 && dest) { + // Terminating '\0' is not printed iff *src is cleared. + SIZE_T write_cnt = res + !(*src); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + } return res; } @@ -1620,13 +1629,16 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms, SIZE_T len, void *ps) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, wcsnrtombs, dest, src, nms, len, ps); - if (src) { + if (nms) { COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); - if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms); + COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms); } SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps); - if (res != (SIZE_T) - 1 && dest) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res + 1); + if (res != (SIZE_T)-1 && dest && nms) { + // Terminating '\0' is not printed iff *src is cleared. + SIZE_T write_cnt = res + !(*src); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + } return res; }