<div dir="ltr">Could you please take a look <a href="http://lab.llvm.org:8011/builders/sanitizer-windows/builds/8551" class="cremed">http://lab.llvm.org:8011/builders/sanitizer-windows/builds/8551</a> ?</div><br><div class="gmail_quote"><div dir="ltr">On Thu, Mar 23, 2017 at 2:52 PM Alex Shlyapnikov via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: alekseyshl<br class="gmail_msg">
Date: Thu Mar 23 16:39:52 2017<br class="gmail_msg">
New Revision: 298650<br class="gmail_msg">
<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=298650&view=rev" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project?rev=298650&view=rev</a><br class="gmail_msg">
Log:<br class="gmail_msg">
[asan] Add an interceptor for strtok<br class="gmail_msg">
<br class="gmail_msg">
Summary:<br class="gmail_msg">
This change addresses <a href="https://github.com/google/sanitizers/issues/766" rel="noreferrer" class="gmail_msg" target="_blank">https://github.com/google/sanitizers/issues/766</a>. I<br class="gmail_msg">
tested the change with make check-asan and the newly added test case.<br class="gmail_msg">
<br class="gmail_msg">
Reviewers: ygribov, kcc, alekseyshl<br class="gmail_msg">
<br class="gmail_msg">
Subscribers: kubamracek, llvm-commits<br class="gmail_msg">
<br class="gmail_msg">
Patch by mrigger<br class="gmail_msg">
<br class="gmail_msg">
Differential Revision: <a href="https://reviews.llvm.org/D30384" rel="noreferrer" class="gmail_msg" target="_blank">https://reviews.llvm.org/D30384</a><br class="gmail_msg">
<br class="gmail_msg">
Added:<br class="gmail_msg">
    compiler-rt/trunk/test/asan/TestCases/strtok.c<br class="gmail_msg">
Modified:<br class="gmail_msg">
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc<br class="gmail_msg">
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc<br class="gmail_msg">
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h<br class="gmail_msg">
<br class="gmail_msg">
Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc?rev=298650&r1=298649&r2=298650&view=diff" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc?rev=298650&r1=298649&r2=298650&view=diff</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc (original)<br class="gmail_msg">
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc Thu Mar 23 16:39:52 2017<br class="gmail_msg">
@@ -495,6 +495,52 @@ INTERCEPTOR(char*, strcasestr, const cha<br class="gmail_msg">
 #define INIT_STRCASESTR<br class="gmail_msg">
 #endif<br class="gmail_msg">
<br class="gmail_msg">
+#if SANITIZER_INTERCEPT_STRTOK<br class="gmail_msg">
+<br class="gmail_msg">
+INTERCEPTOR(char*, strtok, char *str, const char *delimiters) {<br class="gmail_msg">
+  void *ctx;<br class="gmail_msg">
+  COMMON_INTERCEPTOR_ENTER(ctx, strtok, str, delimiters);<br class="gmail_msg">
+  if (!common_flags()->intercept_strtok) {<br class="gmail_msg">
+    return REAL(strtok)(str, delimiters);<br class="gmail_msg">
+  }<br class="gmail_msg">
+  if (common_flags()->strict_string_checks) {<br class="gmail_msg">
+    // If strict_string_checks is enabled, we check the whole first argument<br class="gmail_msg">
+    // string on the first call (strtok saves this string in a static buffer<br class="gmail_msg">
+    // for subsequent calls). We do not need to check strtok's result.<br class="gmail_msg">
+    // As the delimiters can change, we check them every call.<br class="gmail_msg">
+    if (str != nullptr) {<br class="gmail_msg">
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1);<br class="gmail_msg">
+    }<br class="gmail_msg">
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, delimiters,<br class="gmail_msg">
+                                  REAL(strlen)(delimiters) + 1);<br class="gmail_msg">
+    return REAL(strtok)(str, delimiters);<br class="gmail_msg">
+  } else {<br class="gmail_msg">
+    // However, when strict_string_checks is disabled we cannot check the<br class="gmail_msg">
+    // whole string on the first call. Instead, we check the result string<br class="gmail_msg">
+    // which is guaranteed to be a NULL-terminated substring of the first<br class="gmail_msg">
+    // argument. We also conservatively check one character of str and the<br class="gmail_msg">
+    // delimiters.<br class="gmail_msg">
+    if (str != nullptr) {<br class="gmail_msg">
+      COMMON_INTERCEPTOR_READ_STRING(ctx, str, 1);<br class="gmail_msg">
+    }<br class="gmail_msg">
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, delimiters, 1);<br class="gmail_msg">
+    char *result = REAL(strtok)(str, delimiters);<br class="gmail_msg">
+    if (result != nullptr) {<br class="gmail_msg">
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, result, REAL(strlen)(result) + 1);<br class="gmail_msg">
+    } else if (str != nullptr) {<br class="gmail_msg">
+      // No delimiter were found, it's safe to assume that the entire str was<br class="gmail_msg">
+      // scanned.<br class="gmail_msg">
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1);<br class="gmail_msg">
+    }<br class="gmail_msg">
+    return result;<br class="gmail_msg">
+  }<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+#define INIT_STRTOK COMMON_INTERCEPT_FUNCTION(strtok)<br class="gmail_msg">
+#else<br class="gmail_msg">
+#define INIT_STRTOK<br class="gmail_msg">
+#endif<br class="gmail_msg">
+<br class="gmail_msg">
 #if SANITIZER_INTERCEPT_MEMMEM<br class="gmail_msg">
 DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, uptr called_pc,<br class="gmail_msg">
                               const void *s1, SIZE_T len1, const void *s2,<br class="gmail_msg">
@@ -6079,6 +6125,7 @@ static void InitializeCommonInterceptors<br class="gmail_msg">
   INIT_STRCHRNUL;<br class="gmail_msg">
   INIT_STRRCHR;<br class="gmail_msg">
   INIT_STRSPN;<br class="gmail_msg">
+  INIT_STRTOK;<br class="gmail_msg">
   INIT_STRPBRK;<br class="gmail_msg">
   INIT_MEMSET;<br class="gmail_msg">
   INIT_MEMMOVE;<br class="gmail_msg">
<br class="gmail_msg">
Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc?rev=298650&r1=298649&r2=298650&view=diff" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc?rev=298650&r1=298649&r2=298650&view=diff</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc (original)<br class="gmail_msg">
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_flags.inc Thu Mar 23 16:39:52 2017<br class="gmail_msg">
@@ -193,6 +193,9 @@ COMMON_FLAG(bool, intercept_strstr, true<br class="gmail_msg">
 COMMON_FLAG(bool, intercept_strspn, true,<br class="gmail_msg">
             "If set, uses custom wrappers for strspn and strcspn function "<br class="gmail_msg">
             "to find more errors.")<br class="gmail_msg">
+COMMON_FLAG(bool, intercept_strtok, true,<br class="gmail_msg">
+            "If set, uses a custom wrapper for the strtok function "<br class="gmail_msg">
+            "to find more errors.")<br class="gmail_msg">
 COMMON_FLAG(bool, intercept_strpbrk, true,<br class="gmail_msg">
             "If set, uses custom wrappers for strpbrk function "<br class="gmail_msg">
             "to find more errors.")<br class="gmail_msg">
<br class="gmail_msg">
Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h?rev=298650&r1=298649&r2=298650&view=diff" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h?rev=298650&r1=298649&r2=298650&view=diff</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h (original)<br class="gmail_msg">
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h Thu Mar 23 16:39:52 2017<br class="gmail_msg">
@@ -74,6 +74,7 @@<br class="gmail_msg">
 #define SANITIZER_INTERCEPT_STRCMP 1<br class="gmail_msg">
 #define SANITIZER_INTERCEPT_STRSTR 1<br class="gmail_msg">
 #define SANITIZER_INTERCEPT_STRCASESTR SI_NOT_WINDOWS<br class="gmail_msg">
+#define SANITIZER_INTERCEPT_STRTOK 1<br class="gmail_msg">
 #define SANITIZER_INTERCEPT_STRCHR 1<br class="gmail_msg">
 #define SANITIZER_INTERCEPT_STRCHRNUL SI_UNIX_NOT_MAC<br class="gmail_msg">
 #define SANITIZER_INTERCEPT_STRRCHR 1<br class="gmail_msg">
<br class="gmail_msg">
Added: compiler-rt/trunk/test/asan/TestCases/strtok.c<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/strtok.c?rev=298650&view=auto" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/strtok.c?rev=298650&view=auto</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- compiler-rt/trunk/test/asan/TestCases/strtok.c (added)<br class="gmail_msg">
+++ compiler-rt/trunk/test/asan/TestCases/strtok.c Thu Mar 23 16:39:52 2017<br class="gmail_msg">
@@ -0,0 +1,108 @@<br class="gmail_msg">
+// RUN: %clang_asan %s -o %t<br class="gmail_msg">
+<br class="gmail_msg">
+// Test overflows with strict_string_checks<br class="gmail_msg">
+<br class="gmail_msg">
+// RUN: %env_asan_opts=strict_string_checks=true not %run %t test1 2>&1 | \<br class="gmail_msg">
+// RUN:    FileCheck %s --check-prefix=CHECK1<br class="gmail_msg">
+// RUN: %env_asan_opts=intercept_strtok=false%run %t test1 2>&1<br class="gmail_msg">
+// RUN: %env_asan_opts=strict_string_checks=true not %run %t test2 2>&1 | \<br class="gmail_msg">
+// RUN:    FileCheck %s --check-prefix=CHECK2<br class="gmail_msg">
+// RUN: %env_asan_opts=intercept_strtok=false %run %t test2 2>&1<br class="gmail_msg">
+// RUN: %env_asan_opts=strict_string_checks=true not %run %t test3 2>&1 | \<br class="gmail_msg">
+// RUN:    FileCheck %s --check-prefix=CHECK3<br class="gmail_msg">
+// RUN: %env_asan_opts=intercept_strtok=false %run %t test3 2>&1<br class="gmail_msg">
+// RUN: %env_asan_opts=strict_string_checks=true %run %t test4 2>&1<br class="gmail_msg">
+// RUN: %env_asan_opts=intercept_strtok=false %run %t test4 2>&1<br class="gmail_msg">
+<br class="gmail_msg">
+// Test overflows with !strict_string_checks<br class="gmail_msg">
+// RUN: %env_asan_opts=strict_string_checks=false not %run %t test5 2>&1 | \<br class="gmail_msg">
+// RUN:    FileCheck %s --check-prefix=CHECK5<br class="gmail_msg">
+// RUN: %env_asan_opts=intercept_strtok=false %run %t test5 2>&1<br class="gmail_msg">
+// RUN: %env_asan_opts=strict_string_checks=false not %run %t test6 2>&1 | \<br class="gmail_msg">
+// RUN:    FileCheck %s --check-prefix=CHECK6<br class="gmail_msg">
+// RUN: %env_asan_opts=intercept_strtok=false %run %t test6 2>&1<br class="gmail_msg">
+<br class="gmail_msg">
+<br class="gmail_msg">
+#include <assert.h><br class="gmail_msg">
+#include <string.h><br class="gmail_msg">
+#include <sanitizer/asan_interface.h><br class="gmail_msg">
+<br class="gmail_msg">
+// Check that we find overflows in the delimiters on the first call<br class="gmail_msg">
+// with strict_string_checks.<br class="gmail_msg">
+void test1() {<br class="gmail_msg">
+  char *token;<br class="gmail_msg">
+  char s[4] = "abc";<br class="gmail_msg">
+  char token_delimiter[2] = "b";<br class="gmail_msg">
+  __asan_poison_memory_region ((char *)&token_delimiter[1], 2);<br class="gmail_msg">
+  token = strtok(s, token_delimiter);<br class="gmail_msg">
+  // CHECK1:'token_delimiter' <== Memory access at offset {{[0-9]+}} partially overflows this variable<br class="gmail_msg">
+  assert(strcmp(token, "a") == 0);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+// Check that we find overflows in the delimiters on the second call (str == NULL)<br class="gmail_msg">
+// with strict_string_checks.<br class="gmail_msg">
+void test2() {<br class="gmail_msg">
+  char *token;<br class="gmail_msg">
+  char s[4] = "abc";<br class="gmail_msg">
+  char token_delimiter[2] = "b";<br class="gmail_msg">
+  token = strtok(s, token_delimiter);<br class="gmail_msg">
+  assert(strcmp(token, "a") == 0);<br class="gmail_msg">
+  __asan_poison_memory_region ((char *)&token_delimiter[1], 2);<br class="gmail_msg">
+  token = strtok(NULL, token_delimiter);<br class="gmail_msg">
+  // CHECK2:'token_delimiter' <== Memory access at offset {{[0-9]+}} partially overflows this variable<br class="gmail_msg">
+  assert(strcmp(token, "c") == 0);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+// Check that we find overflows in the string (only on the first call) with strict_string_checks.<br class="gmail_msg">
+void test3() {<br class="gmail_msg">
+  char *token;<br class="gmail_msg">
+  char s[4] = "abc";<br class="gmail_msg">
+  char token_delimiter[2] = "b";<br class="gmail_msg">
+  __asan_poison_memory_region ((char *)&s[3], 2);<br class="gmail_msg">
+  token = strtok(s, token_delimiter);<br class="gmail_msg">
+  // CHECK3:'s' <== Memory access at offset {{[0-9]+}} partially overflows this variable<br class="gmail_msg">
+  assert(token == s);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+// Check that we do not crash when strtok returns NULL with strict_string_checks.<br class="gmail_msg">
+void test4() {<br class="gmail_msg">
+  char *token;<br class="gmail_msg">
+  char s[] = "";<br class="gmail_msg">
+  char token_delimiter[] = "a";<br class="gmail_msg">
+  token = strtok(s, token_delimiter);<br class="gmail_msg">
+  assert(token == NULL);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+// Check that we find overflows in the string (only on the first call) with !strict_string_checks.<br class="gmail_msg">
+void test5() {<br class="gmail_msg">
+  char *token;<br class="gmail_msg">
+  char s[4] = "abc";<br class="gmail_msg">
+  char token_delimiter[2] = "d";<br class="gmail_msg">
+  __asan_poison_memory_region ((char *)&s[2], 2);<br class="gmail_msg">
+  __asan_poison_memory_region ((char *)&token_delimiter[1], 2);<br class="gmail_msg">
+  token = strtok(s, token_delimiter);<br class="gmail_msg">
+  // CHECK5:'s' <== Memory access at offset {{[0-9]+}} partially overflows this variable<br class="gmail_msg">
+  assert(token == s);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+// Check that we find overflows in the delimiters (only on the first call) with !strict_string_checks.<br class="gmail_msg">
+void test6() {<br class="gmail_msg">
+  char *token;<br class="gmail_msg">
+  char s[4] = "abc";<br class="gmail_msg">
+  char token_delimiter[1] = {'d'};<br class="gmail_msg">
+  __asan_poison_memory_region ((char *)&token_delimiter[1], 2);<br class="gmail_msg">
+  token = strtok(s, &token_delimiter[1]);<br class="gmail_msg">
+  // CHECK6:'token_delimiter' <== Memory access at offset {{[0-9]+}} overflows this variable<br class="gmail_msg">
+  assert(strcmp(token, "abc") == 0);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+int main(int argc, char **argv) {<br class="gmail_msg">
+  if (argc != 2) return 1;<br class="gmail_msg">
+  if (!strcmp(argv[1], "test1")) test1();<br class="gmail_msg">
+  if (!strcmp(argv[1], "test2")) test2();<br class="gmail_msg">
+  if (!strcmp(argv[1], "test3")) test3();<br class="gmail_msg">
+  if (!strcmp(argv[1], "test4")) test4();<br class="gmail_msg">
+  if (!strcmp(argv[1], "test5")) test5();<br class="gmail_msg">
+  if (!strcmp(argv[1], "test6")) test6();<br class="gmail_msg">
+  return 0;<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
_______________________________________________<br class="gmail_msg">
llvm-commits mailing list<br class="gmail_msg">
<a href="mailto:llvm-commits@lists.llvm.org" class="gmail_msg" target="_blank">llvm-commits@lists.llvm.org</a><br class="gmail_msg">
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" class="gmail_msg" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br class="gmail_msg">
</blockquote></div>