1 // RUN: %clang_analyze_cc1 -verify %s \ 2 // RUN: -analyzer-checker=core \ 3 // RUN: -analyzer-checker=unix.cstring \ 4 // RUN: -analyzer-checker=alpha.unix.cstring \ 5 // RUN: -analyzer-disable-checker=alpha.unix.cstring.UninitializedRead \ 6 // RUN: -analyzer-checker=debug.ExprInspection \ 7 // RUN: -analyzer-config eagerly-assume=false 8 // 9 // RUN: %clang_analyze_cc1 -verify %s -DUSE_BUILTINS \ 10 // RUN: -analyzer-checker=core \ 11 // RUN: -analyzer-checker=unix.cstring \ 12 // RUN: -analyzer-checker=alpha.unix.cstring \ 13 // RUN: -analyzer-disable-checker=alpha.unix.cstring.UninitializedRead \ 14 // RUN: -analyzer-checker=debug.ExprInspection \ 15 // RUN: -analyzer-config eagerly-assume=false 16 17 //===----------------------------------------------------------------------=== 18 // Declarations 19 //===----------------------------------------------------------------------=== 20 21 // Some functions are implemented as builtins. These should be #defined as 22 // BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined. 23 24 #ifdef USE_BUILTINS 25 # define BUILTIN(f) __builtin_ ## f 26 #else /* USE_BUILTINS */ 27 # define BUILTIN(f) f 28 #endif /* USE_BUILTINS */ 29 30 typedef __SIZE_TYPE__ size_t; 31 typedef __WCHAR_TYPE__ wchar_t; 32 33 void clang_analyzer_eval(int); 34 35 //===----------------------------------------------------------------------=== 36 // wwmemcpy() 37 //===----------------------------------------------------------------------=== 38 39 #define wmemcpy BUILTIN(wmemcpy) 40 wchar_t *wmemcpy(wchar_t *restrict s1, const wchar_t *restrict s2, size_t n); 41 42 void wmemcpy0 (void) { 43 wchar_t src[] = {1, 2, 3, 4}; 44 wchar_t dst[4] = {0}; 45 46 wmemcpy(dst, src, 4); // no-warning 47 48 clang_analyzer_eval(wmemcpy(dst, src, 4) == dst); // expected-warning{{TRUE}} 49 50 // If we actually model the copy, we can make this known. 51 // The important thing for now is that the old value has been invalidated. 52 clang_analyzer_eval(dst[0] != 0); // expected-warning{{UNKNOWN}} 53 } 54 55 void wmemcpy1 (void) { 56 wchar_t src[] = {1, 2, 3, 4}; 57 wchar_t dst[10]; 58 59 wmemcpy(dst, src, 5); // expected-warning{{Memory copy function accesses out-of-bound array element}} 60 } 61 62 void wmemcpy2 (void) { 63 wchar_t src[] = {1, 2, 3, 4}; 64 wchar_t dst[1]; 65 66 wmemcpy(dst, src, 4); // expected-warning {{Memory copy function overflows the destination buffer}} 67 } 68 69 void wmemcpy3 (void) { 70 wchar_t src[] = {1, 2, 3, 4}; 71 wchar_t dst[3]; 72 73 wmemcpy(dst+1, src+2, 2); // no-warning 74 } 75 76 void wmemcpy4 (void) { 77 wchar_t src[] = {1, 2, 3, 4}; 78 wchar_t dst[10]; 79 80 wmemcpy(dst+2, src+2, 3); // expected-warning{{Memory copy function accesses out-of-bound array element}} 81 } 82 83 void wmemcpy5(void) { 84 wchar_t src[] = {1, 2, 3, 4}; 85 wchar_t dst[3]; 86 87 wmemcpy(dst + 2, src + 2, 2); // expected-warning{{Memory copy function overflows the destination buffer}} 88 } 89 90 void wmemcpy6(void) { 91 wchar_t a[4] = {0}; 92 wmemcpy(a, a, 2); // expected-warning{{overlapping}} 93 } 94 95 void wmemcpy7(void) { 96 wchar_t a[4] = {0}; 97 wmemcpy(a+2, a+1, 2); // expected-warning{{overlapping}} 98 } 99 100 void wmemcpy8(void) { 101 wchar_t a[4] = {0}; 102 wmemcpy(a+1, a+2, 2); // expected-warning{{overlapping}} 103 } 104 105 void wmemcpy9(void) { 106 wchar_t a[4] = {0}; 107 wmemcpy(a+2, a+1, 1); // no-warning 108 wmemcpy(a+1, a+2, 1); // no-warning 109 } 110 111 void wmemcpy10(void) { 112 wchar_t a[4] = {0}; 113 wmemcpy(0, a, 1); // expected-warning{{Null pointer passed as 1st argument to memory copy function}} 114 } 115 116 void wmemcpy11(void) { 117 wchar_t a[4] = {0}; 118 wmemcpy(a, 0, 1); // expected-warning{{Null pointer passed as 2nd argument to memory copy function}} 119 } 120 121 void wmemcpy12(void) { 122 wchar_t a[4] = {0}; 123 wmemcpy(0, a, 0); // no-warning 124 } 125 126 void wmemcpy13(void) { 127 wchar_t a[4] = {0}; 128 wmemcpy(a, 0, 0); // no-warning 129 } 130 131 void wmemcpy_unknown_size (size_t n) { 132 wchar_t a[4], b[4] = {1}; 133 clang_analyzer_eval(wmemcpy(a, b, n) == a); // expected-warning{{TRUE}} 134 } 135 136 void wmemcpy_unknown_size_warn (size_t n) { 137 wchar_t a[4]; 138 void *result = wmemcpy(a, 0, n); // expected-warning{{Null pointer passed as 2nd argument to memory copy function}} 139 clang_analyzer_eval(result == a); // no-warning (above is fatal) 140 } 141 142 //===----------------------------------------------------------------------=== 143 // wcslen() 144 //===----------------------------------------------------------------------=== 145 146 #define wcslen BUILTIN(wcslen) 147 size_t wcslen(const wchar_t *s); 148 149 void wcslen_constant0(void) { 150 clang_analyzer_eval(wcslen(L"123") == 3); // expected-warning{{TRUE}} 151 } 152 153 void wcslen_constant1(void) { 154 const wchar_t *a = L"123"; 155 clang_analyzer_eval(wcslen(a) == 3); // expected-warning{{TRUE}} 156 } 157 158 void wcslen_constant2(wchar_t x) { 159 wchar_t a[] = L"123"; 160 clang_analyzer_eval(wcslen(a) == 3); // expected-warning{{TRUE}} 161 162 a[0] = x; 163 clang_analyzer_eval(wcslen(a) == 3); // expected-warning{{UNKNOWN}} 164 } 165 166 size_t wcslen_null(void) { 167 return wcslen(0); // expected-warning{{Null pointer passed as 1st argument to string length function}} 168 } 169 170 size_t wcslen_fn(void) { 171 return wcslen((wchar_t*)&wcslen_fn); // expected-warning{{Argument to string length function is the address of the function 'wcslen_fn', which is not a null-terminated string}} 172 } 173 174 size_t wcslen_nonloc(void) { 175 label: 176 return wcslen((wchar_t*)&&label); // expected-warning{{Argument to string length function is the address of the label 'label', which is not a null-terminated string}} 177 } 178 179 void wcslen_subregion(void) { 180 struct two_strings { wchar_t a[2], b[2]; }; 181 extern void use_two_strings(struct two_strings *); 182 183 struct two_strings z; 184 use_two_strings(&z); 185 186 size_t a = wcslen(z.a); 187 z.b[0] = 5; 188 size_t b = wcslen(z.a); 189 if (a == 0) 190 clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} 191 192 use_two_strings(&z); 193 194 size_t c = wcslen(z.a); 195 if (a == 0) 196 clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} 197 } 198 199 extern void use_string(wchar_t *); 200 void wcslen_argument(wchar_t *x) { 201 size_t a = wcslen(x); 202 size_t b = wcslen(x); 203 if (a == 0) 204 clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} 205 206 use_string(x); 207 208 size_t c = wcslen(x); 209 if (a == 0) 210 clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} 211 } 212 213 extern wchar_t global_str[]; 214 void wcslen_global(void) { 215 size_t a = wcslen(global_str); 216 size_t b = wcslen(global_str); 217 if (a == 0) { 218 clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} 219 // Make sure clang_analyzer_eval does not invalidate globals. 220 clang_analyzer_eval(wcslen(global_str) == 0); // expected-warning{{TRUE}} 221 } 222 223 // Call a function with unknown effects, which should invalidate globals. 224 use_string(0); 225 226 size_t c = wcslen(global_str); 227 if (a == 0) 228 clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} 229 } 230 231 void wcslen_indirect(wchar_t *x) { 232 size_t a = wcslen(x); 233 wchar_t *p = x; 234 wchar_t **p2 = &p; 235 size_t b = wcslen(x); 236 if (a == 0) 237 clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} 238 239 extern void use_string_ptr(wchar_t*const*); 240 use_string_ptr(p2); 241 242 size_t c = wcslen(x); 243 if (a == 0) 244 clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} 245 } 246 247 void wcslen_indirect2(wchar_t *x) { 248 size_t a = wcslen(x); 249 wchar_t *p = x; 250 wchar_t **p2 = &p; 251 extern void use_string_ptr2(wchar_t**); 252 use_string_ptr2(p2); 253 254 size_t c = wcslen(x); 255 if (a == 0) 256 clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} 257 } 258 259 void wcslen_liveness(const wchar_t *x) { 260 if (wcslen(x) < 5) 261 return; 262 clang_analyzer_eval(wcslen(x) < 5); // expected-warning{{FALSE}} 263 } 264 265 266 size_t wcslenWrapper(const wchar_t *str) { 267 return wcslen(str); 268 } 269 270 extern void invalidate(wchar_t *s); 271 272 void testwcslenCallee(void) { 273 wchar_t str[42]; 274 invalidate(str); 275 size_t lenBefore = wcslenWrapper(str); 276 invalidate(str); 277 size_t lenAfter = wcslenWrapper(str); 278 clang_analyzer_eval(lenBefore == lenAfter); // expected-warning{{UNKNOWN}} 279 } 280 281 //===----------------------------------------------------------------------=== 282 // wcsnlen() 283 //===----------------------------------------------------------------------=== 284 285 size_t wcsnlen(const wchar_t *s, size_t maxlen); 286 287 void wcsnlen_constant0(void) { 288 clang_analyzer_eval(wcsnlen(L"123", 10) == 3); // expected-warning{{TRUE}} 289 } 290 291 void wcsnlen_constant1(void) { 292 const wchar_t *a = L"123"; 293 clang_analyzer_eval(wcsnlen(a, 10) == 3); // expected-warning{{TRUE}} 294 } 295 296 void wcsnlen_constant2(char x) { 297 wchar_t a[] = L"123"; 298 clang_analyzer_eval(wcsnlen(a, 10) == 3); // expected-warning{{TRUE}} 299 a[0] = x; 300 clang_analyzer_eval(wcsnlen(a, 10) == 3); // expected-warning{{UNKNOWN}} 301 } 302 303 void wcsnlen_constant4(void) { 304 clang_analyzer_eval(wcsnlen(L"123456", 3) == 3); // expected-warning{{TRUE}} 305 } 306 307 void wcsnlen_constant5(void) { 308 const wchar_t *a = L"123456"; 309 clang_analyzer_eval(wcsnlen(a, 3) == 3); // expected-warning{{TRUE}} 310 } 311 312 void wcsnlen_constant6(char x) { 313 wchar_t a[] = L"123456"; 314 clang_analyzer_eval(wcsnlen(a, 3) == 3); // expected-warning{{TRUE}} 315 a[0] = x; 316 clang_analyzer_eval(wcsnlen(a, 3) == 3); // expected-warning{{UNKNOWN}} 317 } 318 319 size_t wcsnlen_null(void) { 320 return wcsnlen(0, 3); // expected-warning{{Null pointer passed as 1st argument to string length function}} 321 } 322 323 size_t wcsnlen_fn(void) { 324 return wcsnlen((wchar_t*)&wcsnlen_fn, 3); // expected-warning{{Argument to string length function is the address of the function 'wcsnlen_fn', which is not a null-terminated string}} 325 } 326 327 size_t wcsnlen_nonloc(void) { 328 label: 329 return wcsnlen((wchar_t*)&&label, 3); // expected-warning{{Argument to string length function is the address of the label 'label', which is not a null-terminated string}} 330 } 331 332 void wcsnlen_zero(void) { 333 clang_analyzer_eval(wcsnlen(L"abc", 0) == 0); // expected-warning{{TRUE}} 334 clang_analyzer_eval(wcsnlen(0, 0) == 0); // expected-warning{{TRUE}} 335 } 336 337 size_t wcsnlen_compound_literal(void) { 338 // This used to crash because we don't model the string lengths of 339 // compound literals. 340 return wcsnlen((wchar_t[]) { 'a', 'b', 0 }, 1); 341 } 342 343 size_t wcsnlen_unknown_limit(float f) { 344 // This used to crash because we don't model the integer values of floats. 345 return wcsnlen(L"abc", (int)f); 346 } 347 348 void wcsnlen_is_not_wcslen(wchar_t *x) { 349 clang_analyzer_eval(wcsnlen(x, 10) == wcslen(x)); // expected-warning{{UNKNOWN}} 350 } 351 352 void wcsnlen_at_limit(wchar_t *x) { 353 size_t len = wcsnlen(x, 10); 354 clang_analyzer_eval(len <= 10); // expected-warning{{TRUE}} 355 clang_analyzer_eval(len == 10); // expected-warning{{UNKNOWN}} 356 clang_analyzer_eval(len < 10); // expected-warning{{UNKNOWN}} 357 } 358 359 void wcsnlen_at_actual(size_t limit) { 360 size_t len = wcsnlen(L"abc", limit); 361 clang_analyzer_eval(len <= 3); // expected-warning{{TRUE}} 362 // This is due to eager assertion in wcsnlen. 363 if (limit == 0) { 364 clang_analyzer_eval(len == 0); // expected-warning{{TRUE}} 365 } else { 366 clang_analyzer_eval(len == 3); // expected-warning{{UNKNOWN}} 367 clang_analyzer_eval(len < 3); // expected-warning{{UNKNOWN}} 368 } 369 } 370 371 //===----------------------------------------------------------------------=== 372 // other tests 373 //===----------------------------------------------------------------------=== 374 375 static const wchar_t w_str[] = L"Hello world"; 376 377 void wmemcpy_sizeof(void) { 378 wchar_t a[32]; 379 wmemcpy(a, w_str, sizeof(w_str) / sizeof(w_str[0])); 380 wmemcpy(a, w_str, (sizeof(w_str) / sizeof(w_str[0])) + 1); // expected-warning {{Memory copy function accesses out-of-bound array element}} 381 } 382 383 void wmemcpy_wcslen(void) { 384 wchar_t a[32]; 385 // FIXME: This should work with 'w_str' instead of 'w_str1' 386 const wchar_t w_str1[] = L"Hello world"; 387 wmemcpy(a, w_str1, wcslen(w_str1) + 1); 388 wmemcpy(a, w_str1, wcslen(w_str1) + 2); // expected-warning {{Memory copy function accesses out-of-bound array element}} 389 } 390