| 1 | // RUN: %clang_asan %s -o %t |
| 2 | |
| 3 | // Test overflows with strict_string_checks |
| 4 | |
| 5 | // RUN: %env_asan_opts=strict_string_checks=true not %run %t test1 2>&1 | \ |
| 6 | // RUN: FileCheck %s --check-prefix=CHECK1 |
| 7 | // RUN: %env_asan_opts=intercept_strtok=false %run %t test1 2>&1 |
| 8 | // RUN: %env_asan_opts=strict_string_checks=true not %run %t test2 2>&1 | \ |
| 9 | // RUN: FileCheck %s --check-prefix=CHECK2 |
| 10 | // RUN: %env_asan_opts=intercept_strtok=false %run %t test2 2>&1 |
| 11 | // RUN: %env_asan_opts=strict_string_checks=true not %run %t test3 2>&1 | \ |
| 12 | // RUN: FileCheck %s --check-prefix=CHECK3 |
| 13 | // RUN: %env_asan_opts=intercept_strtok=false %run %t test3 2>&1 |
| 14 | // RUN: %env_asan_opts=strict_string_checks=true %run %t test4 2>&1 |
| 15 | // RUN: %env_asan_opts=intercept_strtok=false %run %t test4 2>&1 |
| 16 | |
| 17 | // Test overflows with !strict_string_checks |
| 18 | // RUN: %env_asan_opts=strict_string_checks=false not %run %t test5 2>&1 | \ |
| 19 | // RUN: FileCheck %s --check-prefix=CHECK5 |
| 20 | // RUN: %env_asan_opts=intercept_strtok=false %run %t test5 2>&1 |
| 21 | // RUN: %env_asan_opts=strict_string_checks=false not %run %t test6 2>&1 | \ |
| 22 | // RUN: FileCheck %s --check-prefix=CHECK6 |
| 23 | // RUN: %env_asan_opts=intercept_strtok=false %run %t test6 2>&1 |
| 24 | |
| 25 | |
| 26 | #include <assert.h> |
| 27 | #include <string.h> |
| 28 | #include <sanitizer/asan_interface.h> |
| 29 | |
| 30 | // Check that we find overflows in the delimiters on the first call |
| 31 | // with strict_string_checks. |
| 32 | void test1() { |
| 33 | char *token; |
| 34 | char s[4] = "abc" ; |
| 35 | char token_delimiter[2] = "b" ; |
| 36 | __asan_poison_memory_region (addr: (char *)&token_delimiter[1], size: 2); |
| 37 | token = strtok(s: s, delim: token_delimiter); |
| 38 | // CHECK1: 'token_delimiter'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable |
| 39 | } |
| 40 | |
| 41 | // Check that we find overflows in the delimiters on the second call (str == NULL) |
| 42 | // with strict_string_checks. |
| 43 | void test2() { |
| 44 | char *token; |
| 45 | char s[4] = "abc" ; |
| 46 | char token_delimiter[2] = "b" ; |
| 47 | token = strtok(s: s, delim: token_delimiter); |
| 48 | assert(strcmp(token, "a" ) == 0); |
| 49 | __asan_poison_memory_region (addr: (char *)&token_delimiter[1], size: 2); |
| 50 | token = strtok(NULL, delim: token_delimiter); |
| 51 | // CHECK2: 'token_delimiter'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable |
| 52 | } |
| 53 | |
| 54 | // Check that we find overflows in the string (only on the first call) with strict_string_checks. |
| 55 | void test3() { |
| 56 | char *token; |
| 57 | char s[4] = "abc" ; |
| 58 | char token_delimiter[2] = "b" ; |
| 59 | __asan_poison_memory_region (addr: (char *)&s[3], size: 2); |
| 60 | token = strtok(s: s, delim: token_delimiter); |
| 61 | // CHECK3: 's'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable |
| 62 | } |
| 63 | |
| 64 | // Check that we do not crash when strtok returns NULL with strict_string_checks. |
| 65 | void test4() { |
| 66 | char *token; |
| 67 | char s[] = "" ; |
| 68 | char token_delimiter[] = "a" ; |
| 69 | token = strtok(s: s, delim: token_delimiter); |
| 70 | assert(token == NULL); |
| 71 | } |
| 72 | |
| 73 | // Check that we find overflows in the string (only on the first call) with !strict_string_checks. |
| 74 | void test5() { |
| 75 | char *token; |
| 76 | char s[4] = "abc" ; |
| 77 | char token_delimiter[2] = "d" ; |
| 78 | __asan_poison_memory_region (addr: (char *)&s[2], size: 2); |
| 79 | __asan_poison_memory_region (addr: (char *)&token_delimiter[1], size: 2); |
| 80 | token = strtok(s: s, delim: token_delimiter); |
| 81 | // CHECK5: 's'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable |
| 82 | } |
| 83 | |
| 84 | // Check that we find overflows in the delimiters (only on the first call) with !strict_string_checks. |
| 85 | void test6() { |
| 86 | char *token; |
| 87 | char s[4] = "abc" ; |
| 88 | char token_delimiter[1] = {'d'}; |
| 89 | __asan_poison_memory_region (addr: (char *)&token_delimiter[1], size: 2); |
| 90 | token = strtok(s: s, delim: &token_delimiter[1]); |
| 91 | // CHECK6: 'token_delimiter'{{.*}} <== Memory access at offset {{[0-9]+}} overflows this variable |
| 92 | } |
| 93 | |
| 94 | int main(int argc, char **argv) { |
| 95 | if (argc != 2) return 1; |
| 96 | if (!strcmp(s1: argv[1], s2: "test1" )) test1(); |
| 97 | if (!strcmp(s1: argv[1], s2: "test2" )) test2(); |
| 98 | if (!strcmp(s1: argv[1], s2: "test3" )) test3(); |
| 99 | if (!strcmp(s1: argv[1], s2: "test4" )) test4(); |
| 100 | if (!strcmp(s1: argv[1], s2: "test5" )) test5(); |
| 101 | if (!strcmp(s1: argv[1], s2: "test6" )) test6(); |
| 102 | return 0; |
| 103 | } |
| 104 | |