1// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s 2// RUN: %clang_cc1 -analyze -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s 3// XFAIL: * 4 5// This file is for tests that may eventually go into string.c, or may be 6// deleted outright. At one point these tests passed, but only because we 7// weren't correctly modelling the behavior of the relevant string functions. 8// The tests aren't incorrect, but require the analyzer to be smarter about 9// conjured values than it currently is. 10 11//===----------------------------------------------------------------------=== 12// Declarations 13//===----------------------------------------------------------------------=== 14 15// Some functions are so similar to each other that they follow the same code 16// path, such as memcpy and __memcpy_chk, or memcmp and bcmp. If VARIANT is 17// defined, make sure to use the variants instead to make sure they are still 18// checked by the analyzer. 19 20// Some functions are implemented as builtins. These should be #defined as 21// BUILTIN(f), which will prepend "__builtin_" if USE_BUILTINS is defined. 22 23// Functions that have variants and are also available as builtins should be 24// declared carefully! See memcpy() for an example. 25 26#ifdef USE_BUILTINS 27# define BUILTIN(f) __builtin_ ## f 28#else /* USE_BUILTINS */ 29# define BUILTIN(f) f 30#endif /* USE_BUILTINS */ 31 32#define NULL 0 33typedef typeof(sizeof(int)) size_t; 34 35void clang_analyzer_eval(int); 36 37//===----------------------------------------------------------------------=== 38// strnlen() 39//===----------------------------------------------------------------------=== 40 41#define strnlen BUILTIN(strnlen) 42size_t strnlen(const char *s, size_t maxlen); 43 44void strnlen_liveness(const char *x) { 45 if (strnlen(x, 10) < 5) 46 return; 47 clang_analyzer_eval(strnlen(x, 10) < 5); // expected-warning{{FALSE}} 48} 49 50void strnlen_subregion() { 51 struct two_stringsn { char a[2], b[2]; }; 52 extern void use_two_stringsn(struct two_stringsn *); 53 54 struct two_stringsn z; 55 use_two_stringsn(&z); 56 57 size_t a = strnlen(z.a, 10); 58 z.b[0] = 5; 59 size_t b = strnlen(z.a, 10); 60 if (a == 0) 61 clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} 62 63 use_two_stringsn(&z); 64 65 size_t c = strnlen(z.a, 10); 66 if (a == 0) 67 clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} 68} 69 70extern void use_stringn(char *); 71void strnlen_argument(char *x) { 72 size_t a = strnlen(x, 10); 73 size_t b = strnlen(x, 10); 74 if (a == 0) 75 clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} 76 77 use_stringn(x); 78 79 size_t c = strnlen(x, 10); 80 if (a == 0) 81 clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} 82} 83 84extern char global_strn[]; 85void strnlen_global() { 86 size_t a = strnlen(global_strn, 10); 87 size_t b = strnlen(global_strn, 10); 88 if (a == 0) 89 clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} 90 91 // Call a function with unknown effects, which should invalidate globals. 92 use_stringn(0); 93 94 size_t c = strnlen(global_strn, 10); 95 if (a == 0) 96 clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} 97} 98 99void strnlen_indirect(char *x) { 100 size_t a = strnlen(x, 10); 101 char *p = x; 102 char **p2 = &p; 103 size_t b = strnlen(x, 10); 104 if (a == 0) 105 clang_analyzer_eval(b == 0); // expected-warning{{TRUE}} 106 107 extern void use_stringn_ptr(char*const*); 108 use_stringn_ptr(p2); 109 110 size_t c = strnlen(x, 10); 111 if (a == 0) 112 clang_analyzer_eval(c == 0); // expected-warning{{UNKNOWN}} 113} 114