Index: asan_interceptors.cc =================================================================== --- asan_interceptors.cc +++ asan_interceptors.cc @@ -538,6 +538,19 @@ return REAL(strcpy)(to, from); // NOLINT } +INTERCEPTOR(char*, strtok, char *str, const char *delimiters) { + void *ctx; + ASAN_INTERCEPTOR_ENTER(ctx, strtok); + ENSURE_ASAN_INITED(); + if (flags()->replace_str) { + uptr del_size = REAL(strlen)(delimiters) + 1; + uptr str_size = REAL(strlen)(str) + 1; + ASAN_READ_RANGE(ctx, delimiters, del_size); + ASAN_READ_RANGE(ctx, str, str_size); + } + return REAL(strtok)(str, delimiters); +} + INTERCEPTOR(char*, strdup, const char *s) { void *ctx; ASAN_INTERCEPTOR_ENTER(ctx, strdup); @@ -716,6 +729,7 @@ ASAN_INTERCEPT_FUNC(strcat); // NOLINT ASAN_INTERCEPT_FUNC(strcpy); // NOLINT ASAN_INTERCEPT_FUNC(wcslen); + ASAN_INTERCEPT_FUNC(strtok); ASAN_INTERCEPT_FUNC(strncat); ASAN_INTERCEPT_FUNC(strncpy); ASAN_INTERCEPT_FUNC(strdup); Index: tests/asan_str_test.cc =================================================================== --- tests/asan_str_test.cc +++ tests/asan_str_test.cc @@ -107,6 +107,27 @@ free(heap_string); } +TEST(AddressSanitizer, StrTokTest) { + size_t size = Ident(100); + char *s = MallocAndMemsetString(size, 'o'); + s[size - 1] = '\0'; + char *delim = Ident((char*)malloc(2)); + delim[0] = ' '; + delim[1] = '\n'; + // Normal call. + strtok(s, s); + // Cause out-of-bounds read by missing NULL terminator. + EXPECT_DEATH(Ident(strtok(s, delim)), RightOOBReadMessage(0)); + EXPECT_DEATH(Ident(strtok(delim, s)), RightOOBReadMessage(0)); + s[size - 1] = 'a'; + EXPECT_DEATH(Ident(strtok(s, s)), RightOOBReadMessage(0)); + // Argument points to not-allocated memory. + EXPECT_DEATH(Ident(strtok(delim-1, delim-1)), LeftOOBReadMessage(1)); + free(s); + free(delim); +} + + #if SANITIZER_TEST_HAS_STRNLEN TEST(AddressSanitizer, StrNLenOOBTest) { size_t size = Ident(123);