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