diff options
-rw-r--r-- | compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc | 17 | ||||
-rw-r--r-- | compiler-rt/test/asan/TestCases/wcrtomb.c | 13 | ||||
-rw-r--r-- | compiler-rt/test/sanitizer_common/TestCases/wcrtomb.c | 36 |
3 files changed, 59 insertions, 7 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index b3be48d7521..bdecf7b0f6a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -3524,13 +3524,16 @@ INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, wcrtomb, dest, src, ps); if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); - // FIXME: under ASan the call below may write to freed memory and corrupt - // its metadata. See - // https://github.com/google/sanitizers/issues/321. - SIZE_T res = REAL(wcrtomb)(dest, src, ps); - if (res != ((SIZE_T)-1) && dest) { - SIZE_T write_cnt = res; - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + + if (!dest) + return REAL(wcrtomb)(dest, src, ps); + + char local_dest[32]; + SIZE_T res = REAL(wcrtomb)(local_dest, src, ps); + if (res != ((SIZE_T)-1)) { + CHECK_LE(res, sizeof(local_dest)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, res); + REAL(memcpy)(dest, local_dest, res); } return res; } diff --git a/compiler-rt/test/asan/TestCases/wcrtomb.c b/compiler-rt/test/asan/TestCases/wcrtomb.c new file mode 100644 index 00000000000..bcfbd146dbb --- /dev/null +++ b/compiler-rt/test/asan/TestCases/wcrtomb.c @@ -0,0 +1,13 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include <stdlib.h> +#include <wchar.h> + +int main() { + char *buff = (char*) malloc(MB_CUR_MAX); + free(buff); + wcrtomb(buff, L'a', NULL); + // CHECK: use-after-free + // CHECK: SUMMARY + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/wcrtomb.c b/compiler-rt/test/sanitizer_common/TestCases/wcrtomb.c new file mode 100644 index 00000000000..64cbd99b9ad --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/wcrtomb.c @@ -0,0 +1,36 @@ +// RUN: %clang %s -o %t && %run %t 2>&1 + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> + +int main(int argc, char **argv) { + mbstate_t state; + memset(&state, 0, sizeof(state)); + + char buff[10]; + size_t res = wcrtomb(buff, L'a', &state); + assert(res == 1); + assert(buff[0] == 'a'); + + res = wcrtomb(buff, L'\0', &state); + assert(res == 1); + assert(buff[0] == '\0'); + + res = wcrtomb(NULL, L'\0', &state); + assert(res == 1); + + res = wcrtomb(buff, L'a', NULL); + assert(res == 1); + assert(buff[0] == 'a'); + + res = wcrtomb(buff, L'\0', NULL); + assert(res == 1); + assert(buff[0] == '\0'); + + res = wcrtomb(NULL, L'\0', NULL); + assert(res == 1); + + return 0; +} |