| 1 | // RUN: %check_clang_tidy --match-partial-fixes %s bugprone-not-null-terminated-result %t -- \ |
| 2 | // RUN: -- -std=c11 -I %S/Inputs/not-null-terminated-result |
| 3 | |
| 4 | #include "not-null-terminated-result-c.h" |
| 5 | |
| 6 | void path_sensitive_unknown_length(char *position, const char *src) { |
| 7 | int length; |
| 8 | length = strlen(src); |
| 9 | position = (char *)memchr(src, '\0', length); |
| 10 | } |
| 11 | |
| 12 | void bad_memchr(char *position, const char *src) { |
| 13 | int length = strlen(src); |
| 14 | position = (char *)memchr(src, '\0', length); |
| 15 | // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: the length is too short to include the null terminator [bugprone-not-null-terminated-result] |
| 16 | // CHECK-FIXES: position = strchr(src, '\0'); |
| 17 | } |
| 18 | |
| 19 | void good_memchr(char *pos, const char *src) { |
| 20 | pos = strchr(src, '\0'); |
| 21 | } |
| 22 | |
| 23 | void bad_strerror_s(int errno) { |
| 24 | char dest[13]; |
| 25 | int length = strlen(strerror(errno)); |
| 26 | strerror_s(dest, length, errno); |
| 27 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'strerror_s' is not null-terminated and missing the last character of the error message [bugprone-not-null-terminated-result] |
| 28 | // CHECK-FIXES: char dest[14]; |
| 29 | // CHECK-FIXES-NEXT: int length = strlen(strerror(errno)); |
| 30 | // CHECK-FIXES-NEXT: strerror_s(dest, length + 1, errno); |
| 31 | } |
| 32 | |
| 33 | void good_strerror_s(int errno) { |
| 34 | char dst[14]; |
| 35 | int length = strlen(strerror(errno)); |
| 36 | strerror_s(dst, length + 1, errno); |
| 37 | } |
| 38 | |
| 39 | int bad_strncmp_1(char *str1, const char *str2) { |
| 40 | int length = strlen(str1) + 1; |
| 41 | return strncmp(str1, str2, length); |
| 42 | // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] |
| 43 | // CHECK-FIXES: strncmp(str1, str2, length - 1); |
| 44 | } |
| 45 | |
| 46 | int good_strncmp_1(char *str1, const char *str2) { |
| 47 | int length = strlen(str1) + 1; |
| 48 | return strncmp(str1, str2, length - 1); |
| 49 | } |
| 50 | |
| 51 | int bad_strncmp_2(char *str2) { |
| 52 | return strncmp(str2, "foobar" , (strlen("foobar" ) + 1)); |
| 53 | // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] |
| 54 | // CHECK-FIXES: strncmp(str2, "foobar", (strlen("foobar"))); |
| 55 | } |
| 56 | |
| 57 | int bad_strncmp_3(char *str3) { |
| 58 | return strncmp(str3, "foobar" , 1 + strlen("foobar" )); |
| 59 | // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] |
| 60 | // CHECK-FIXES: strncmp(str3, "foobar", strlen("foobar")); |
| 61 | } |
| 62 | |
| 63 | int good_strncmp_2_3(char *str) { |
| 64 | return strncmp(str, "foobar" , strlen("foobar" )); |
| 65 | } |
| 66 | |
| 67 | void bad_strxfrm(const char *long_source_name) { |
| 68 | char long_destination_name[13]; |
| 69 | int very_long_length_definition_name = strlen(long_source_name); |
| 70 | strxfrm(long_destination_name, long_source_name, |
| 71 | very_long_length_definition_name); |
| 72 | // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: the result from calling 'strxfrm' is not null-terminated [bugprone-not-null-terminated-result] |
| 73 | // CHECK-FIXES: char long_destination_name[14]; |
| 74 | // CHECK-FIXES-NEXT: int very_long_length_definition_name = strlen(long_source_name); |
| 75 | // CHECK-FIXES-NEXT: strxfrm(long_destination_name, long_source_name, |
| 76 | // CHECK-FIXES-NEXT: very_long_length_definition_name + 1); |
| 77 | } |
| 78 | |
| 79 | void good_strxfrm(const char *long_source_name) { |
| 80 | char long_destination_name[14]; |
| 81 | int very_long_length_definition_name = strlen(long_source_name); |
| 82 | strxfrm(long_destination_name, long_source_name, |
| 83 | very_long_length_definition_name + 1); |
| 84 | } |
| 85 | |