1 // RUN: %check_clang_tidy %s bugprone-suspicious-string-compare %t -- \
2 // RUN: -config='{CheckOptions: \
3 // RUN: [{key: bugprone-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \
4 // RUN: {key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \
5 // RUN: --
6
7 typedef __SIZE_TYPE__ size;
8
9 struct locale_t {
10 void* dummy;
11 } locale;
12
13 static const char A[] = "abc";
14 static const unsigned char U[] = "abc";
15 static const unsigned char V[] = "xyz";
16 static const wchar_t W[] = L"abc";
17
18 int strlen(const char *);
19
20 int memcmp(const void *, const void *, size);
21 int wmemcmp(const wchar_t *, const wchar_t *, size);
22 int memicmp(const void *, const void *, size);
23 int _memicmp(const void *, const void *, size);
24 int _memicmp_l(const void *, const void *, size, locale_t);
25
26 int strcmp(const char *, const char *);
27 int strncmp(const char *, const char *, size);
28 int strcasecmp(const char *, const char *);
29 int strncasecmp(const char *, const char *, size);
30 int stricmp(const char *, const char *);
31 int strcmpi(const char *, const char *);
32 int strnicmp(const char *, const char *, size);
33 int _stricmp(const char *, const char * );
34 int _strnicmp(const char *, const char *, size);
35 int _stricmp_l(const char *, const char *, locale_t);
36 int _strnicmp_l(const char *, const char *, size, locale_t);
37
38 int wcscmp(const wchar_t *, const wchar_t *);
39 int wcsncmp(const wchar_t *, const wchar_t *, size);
40 int wcscasecmp(const wchar_t *, const wchar_t *);
41 int wcsicmp(const wchar_t *, const wchar_t *);
42 int wcsnicmp(const wchar_t *, const wchar_t *, size);
43 int _wcsicmp(const wchar_t *, const wchar_t *);
44 int _wcsnicmp(const wchar_t *, const wchar_t *, size);
45 int _wcsicmp_l(const wchar_t *, const wchar_t *, locale_t);
46 int _wcsnicmp_l(const wchar_t *, const wchar_t *, size, locale_t);
47
48 int _mbscmp(const unsigned char *, const unsigned char *);
49 int _mbsncmp(const unsigned char *, const unsigned char *, size);
50 int _mbsnbcmp(const unsigned char *, const unsigned char *, size);
51 int _mbsnbicmp(const unsigned char *, const unsigned char *, size);
52 int _mbsicmp(const unsigned char *, const unsigned char *);
53 int _mbsnicmp(const unsigned char *, const unsigned char *, size);
54 int _mbscmp_l(const unsigned char *, const unsigned char *, locale_t);
55 int _mbsncmp_l(const unsigned char *, const unsigned char *, size, locale_t);
56 int _mbsicmp_l(const unsigned char *, const unsigned char *, locale_t);
57 int _mbsnicmp_l(const unsigned char *, const unsigned char *, size, locale_t);
58 int _mbsnbcmp_l(const unsigned char *, const unsigned char *, size, locale_t);
59 int _mbsnbicmp_l(const unsigned char *, const unsigned char *, size, locale_t);
60
test_warning_patterns()61 int test_warning_patterns() {
62 if (strcmp(A, "a"))
63 return 0;
64 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [bugprone-suspicious-string-compare]
65 // CHECK-FIXES: if (strcmp(A, "a") != 0)
66
67 if (strcmp(A, "a") == 0 ||
68 strcmp(A, "b"))
69 return 0;
70 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
71 // CHECK-FIXES: strcmp(A, "b") != 0)
72
73 if (strcmp(A, "a") == 1)
74 return 0;
75 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
76
77 if (strcmp(A, "a") == -1)
78 return 0;
79 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
80
81 if (strcmp(A, "a") == true)
82 return 0;
83 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
84
85 if (strcmp(A, "a") < '0')
86 return 0;
87 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
88
89 if (strcmp(A, "a") < 0.)
90 return 0;
91 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast
92 }
93
test_valid_patterns()94 int test_valid_patterns() {
95 // The following cases are valid.
96 if (strcmp(A, "a") < 0)
97 return 0;
98 if (strcmp(A, "a") == 0)
99 return 0;
100 if (strcmp(A, "a") <= 0)
101 return 0;
102
103 if (wcscmp(W, L"a") < 0)
104 return 0;
105 if (wcscmp(W, L"a") == 0)
106 return 0;
107 if (wcscmp(W, L"a") <= 0)
108 return 0;
109
110 return 1;
111 }
112
test_implicit_compare_with_functions()113 int test_implicit_compare_with_functions() {
114
115 if (memcmp(A, "a", 1))
116 return 0;
117 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memcmp' is called without explicitly comparing result
118 // CHECK-FIXES: memcmp(A, "a", 1) != 0)
119
120 if (wmemcmp(W, L"a", 1))
121 return 0;
122 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wmemcmp' is called without explicitly comparing result
123 // CHECK-FIXES: wmemcmp(W, L"a", 1) != 0)
124
125 if (memicmp(A, "a", 1))
126 return 0;
127 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memicmp' is called without explicitly comparing result
128 // CHECK-FIXES: memicmp(A, "a", 1) != 0)
129
130 if (_memicmp(A, "a", 1))
131 return 0;
132 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp' is called without explicitly comparing result
133 // CHECK-FIXES: _memicmp(A, "a", 1) != 0)
134
135 if (_memicmp_l(A, "a", 1, locale))
136 return 0;
137 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp_l' is called without explicitly comparing result
138 // CHECK-FIXES: _memicmp_l(A, "a", 1, locale) != 0)
139
140 if (strcmp(A, "a"))
141 return 0;
142 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
143 // CHECK-FIXES: strcmp(A, "a") != 0)
144
145 if (strncmp(A, "a", 1))
146 return 0;
147 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncmp' is called without explicitly comparing result
148 // CHECK-FIXES: strncmp(A, "a", 1) != 0)
149
150 if (strcasecmp(A, "a"))
151 return 0;
152 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcasecmp' is called without explicitly comparing result
153 // CHECK-FIXES: strcasecmp(A, "a") != 0)
154
155 if (strncasecmp(A, "a", 1))
156 return 0;
157 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncasecmp' is called without explicitly comparing result
158 // CHECK-FIXES: strncasecmp(A, "a", 1) != 0)
159
160 if (stricmp(A, "a"))
161 return 0;
162 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'stricmp' is called without explicitly comparing result
163 // CHECK-FIXES: stricmp(A, "a") != 0)
164
165 if (strcmpi(A, "a"))
166 return 0;
167 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmpi' is called without explicitly comparing result
168 // CHECK-FIXES: strcmpi(A, "a") != 0)
169
170 if (_stricmp(A, "a"))
171 return 0;
172 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp' is called without explicitly comparing result
173 // CHECK-FIXES: _stricmp(A, "a") != 0)
174
175 if (strnicmp(A, "a", 1))
176 return 0;
177 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strnicmp' is called without explicitly comparing result
178 // CHECK-FIXES: strnicmp(A, "a", 1) != 0)
179
180 if (_strnicmp(A, "a", 1))
181 return 0;
182 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp' is called without explicitly comparing result
183 // CHECK-FIXES: _strnicmp(A, "a", 1) != 0)
184
185 if (_stricmp_l(A, "a", locale))
186 return 0;
187 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp_l' is called without explicitly comparing result
188 // CHECK-FIXES: _stricmp_l(A, "a", locale) != 0)
189
190 if (_strnicmp_l(A, "a", 1, locale))
191 return 0;
192 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp_l' is called without explicitly comparing result
193 // CHECK-FIXES: _strnicmp_l(A, "a", 1, locale) != 0)
194
195 if (wcscmp(W, L"a"))
196 return 0;
197 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscmp' is called without explicitly comparing result
198 // CHECK-FIXES: wcscmp(W, L"a") != 0)
199
200 if (wcsncmp(W, L"a", 1))
201 return 0;
202 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsncmp' is called without explicitly comparing result
203 // CHECK-FIXES: wcsncmp(W, L"a", 1) != 0)
204
205 if (wcscasecmp(W, L"a"))
206 return 0;
207 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscasecmp' is called without explicitly comparing result
208 // CHECK-FIXES: wcscasecmp(W, L"a") != 0)
209
210 if (wcsicmp(W, L"a"))
211 return 0;
212 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsicmp' is called without explicitly comparing result
213 // CHECK-FIXES: wcsicmp(W, L"a") != 0)
214
215 if (_wcsicmp(W, L"a"))
216 return 0;
217 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp' is called without explicitly comparing result
218 // CHECK-FIXES: _wcsicmp(W, L"a") != 0)
219
220 if (_wcsicmp_l(W, L"a", locale))
221 return 0;
222 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp_l' is called without explicitly comparing result
223 // CHECK-FIXES: _wcsicmp_l(W, L"a", locale) != 0)
224
225 if (wcsnicmp(W, L"a", 1))
226 return 0;
227 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsnicmp' is called without explicitly comparing result
228 // CHECK-FIXES: wcsnicmp(W, L"a", 1) != 0)
229
230 if (_wcsnicmp(W, L"a", 1))
231 return 0;
232 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp' is called without explicitly comparing result
233 // CHECK-FIXES: _wcsnicmp(W, L"a", 1) != 0)
234
235 if (_wcsnicmp_l(W, L"a", 1, locale))
236 return 0;
237 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp_l' is called without explicitly comparing result
238 // CHECK-FIXES: _wcsnicmp_l(W, L"a", 1, locale) != 0)
239
240 if (_mbscmp(U, V))
241 return 0;
242 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp' is called without explicitly comparing result
243 // CHECK-FIXES: _mbscmp(U, V) != 0)
244
245 if (_mbsncmp(U, V, 1))
246 return 0;
247 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp' is called without explicitly comparing result
248 // CHECK-FIXES: _mbsncmp(U, V, 1) != 0)
249
250 if (_mbsnbcmp(U, V, 1))
251 return 0;
252 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp' is called without explicitly comparing result
253 // CHECK-FIXES: _mbsnbcmp(U, V, 1) != 0)
254
255 if (_mbsnbicmp(U, V, 1))
256 return 0;
257 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp' is called without explicitly comparing result
258 // CHECK-FIXES: _mbsnbicmp(U, V, 1) != 0)
259
260 if (_mbsicmp(U, V))
261 return 0;
262 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp' is called without explicitly comparing result
263 // CHECK-FIXES: _mbsicmp(U, V) != 0)
264
265 if (_mbsnicmp(U, V, 1))
266 return 0;
267 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp' is called without explicitly comparing result
268 // CHECK-FIXES: _mbsnicmp(U, V, 1) != 0)
269
270 if (_mbscmp_l(U, V, locale))
271 return 0;
272 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp_l' is called without explicitly comparing result
273 // CHECK-FIXES: _mbscmp_l(U, V, locale) != 0)
274
275 if (_mbsncmp_l(U, V, 1, locale))
276 return 0;
277 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp_l' is called without explicitly comparing result
278 // CHECK-FIXES: _mbsncmp_l(U, V, 1, locale) != 0)
279
280 if (_mbsicmp_l(U, V, locale))
281 return 0;
282 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp_l' is called without explicitly comparing result
283 // CHECK-FIXES: _mbsicmp_l(U, V, locale) != 0)
284
285 if (_mbsnicmp_l(U, V, 1, locale))
286 return 0;
287 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp_l' is called without explicitly comparing result
288 // CHECK-FIXES: _mbsnicmp_l(U, V, 1, locale) != 0)
289
290 if (_mbsnbcmp_l(U, V, 1, locale))
291 return 0;
292 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp_l' is called without explicitly comparing result
293 // CHECK-FIXES: _mbsnbcmp_l(U, V, 1, locale) != 0)
294
295 if (_mbsnbicmp_l(U, V, 1, locale))
296 return 0;
297 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp_l' is called without explicitly comparing result
298 // CHECK-FIXES: _mbsnbicmp_l(U, V, 1, locale) != 0)
299
300 return 1;
301 }
302
strcmp_wrapper1(const char * a,const char * b)303 int strcmp_wrapper1(const char* a, const char* b) {
304 return strcmp(a, b);
305 }
306
strcmp_wrapper2(const char * a,const char * b)307 int strcmp_wrapper2(const char* a, const char* b) {
308 return (a && b) ? strcmp(a, b) : 0;
309 }
310
311 #define macro_strncmp(s1, s2, n) \
312 (__extension__ (__builtin_constant_p (n) \
313 && ((__builtin_constant_p (s1) \
314 && strlen (s1) < ((size) (n))) \
315 || (__builtin_constant_p (s2) \
316 && strlen (s2) < ((size) (n)))) \
317 ? strcmp (s1, s2) : strncmp (s1, s2, n)))
318
strncmp_macro(const char * a,const char * b)319 int strncmp_macro(const char* a, const char* b) {
320 if (macro_strncmp(a, b, 4))
321 return 0;
322 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
323
324 if (macro_strncmp(a, b, 4) == 2)
325 return 0;
326 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
327
328 if (macro_strncmp(a, b, 4) <= .0)
329 return 0;
330 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast
331
332 if (macro_strncmp(a, b, 4) + 0)
333 return 0;
334 // CHECK-MESSAGES: [[@LINE-2]]:7: warning: results of function 'strcmp' used by operator '+'
335
336 return 1;
337 }
338