1 // Check the basic reporting/warning and the application of constraints. 2 // RUN: %clang_analyze_cc1 %s \ 3 // RUN: -analyzer-checker=core \ 4 // RUN: -analyzer-checker=apiModeling.StdCLibraryFunctions \ 5 // RUN: -analyzer-checker=alpha.unix.StdCLibraryFunctionArgs \ 6 // RUN: -analyzer-checker=debug.StdCLibraryFunctionsTester \ 7 // RUN: -analyzer-checker=debug.ExprInspection \ 8 // RUN: -triple x86_64-unknown-linux-gnu \ 9 // RUN: -verify=report 10 11 // Check the bugpath related to the reports. 12 // RUN: %clang_analyze_cc1 %s \ 13 // RUN: -analyzer-checker=core \ 14 // RUN: -analyzer-checker=apiModeling.StdCLibraryFunctions \ 15 // RUN: -analyzer-checker=alpha.unix.StdCLibraryFunctionArgs \ 16 // RUN: -analyzer-checker=debug.StdCLibraryFunctionsTester \ 17 // RUN: -analyzer-checker=debug.ExprInspection \ 18 // RUN: -triple x86_64-unknown-linux-gnu \ 19 // RUN: -analyzer-output=text \ 20 // RUN: -verify=bugpath 21 22 void clang_analyzer_eval(int); 23 void clang_analyzer_warnIfReached(); 24 25 int glob; 26 27 #define EOF -1 28 29 int isalnum(int); 30 31 void test_alnum_concrete(int v) { 32 int ret = isalnum(256); // \ 33 // report-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \ 34 // bugpath-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \ 35 // bugpath-note{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} 36 (void)ret; 37 } 38 39 void test_alnum_symbolic(int x) { 40 int ret = isalnum(x); // \ 41 // bugpath-note{{Assuming the character is non-alphanumeric}} 42 (void)ret; 43 44 clang_analyzer_eval(EOF <= x && x <= 255); // \ 45 // report-warning{{TRUE}} \ 46 // bugpath-warning{{TRUE}} \ 47 // bugpath-note{{TRUE}} \ 48 // bugpath-note{{Left side of '&&' is true}} \ 49 // bugpath-note{{'x' is <= 255}} 50 } 51 52 void test_alnum_symbolic2(int x) { 53 if (x > 255) { // \ 54 // bugpath-note{{Assuming 'x' is > 255}} \ 55 // bugpath-note{{Taking true branch}} 56 57 int ret = isalnum(x); // \ 58 // report-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \ 59 // bugpath-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \ 60 // bugpath-note{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} 61 62 (void)ret; 63 } 64 } 65 66 int toupper(int); 67 68 void test_toupper_concrete(int v) { 69 int ret = toupper(256); // \ 70 // report-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \ 71 // bugpath-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \ 72 // bugpath-note{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} 73 (void)ret; 74 } 75 76 void test_toupper_symbolic(int x) { 77 int ret = toupper(x); 78 (void)ret; 79 80 clang_analyzer_eval(EOF <= x && x <= 255); // \ 81 // report-warning{{TRUE}} \ 82 // bugpath-warning{{TRUE}} \ 83 // bugpath-note{{TRUE}} \ 84 // bugpath-note{{Left side of '&&' is true}} \ 85 // bugpath-note{{'x' is <= 255}} 86 } 87 88 void test_toupper_symbolic2(int x) { 89 if (x > 255) { // \ 90 // bugpath-note{{Assuming 'x' is > 255}} \ 91 // bugpath-note{{Taking true branch}} 92 93 int ret = toupper(x); // \ 94 // report-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \ 95 // bugpath-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \ 96 // bugpath-note{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} 97 98 (void)ret; 99 } 100 } 101 102 int tolower(int); 103 104 void test_tolower_concrete(int v) { 105 int ret = tolower(256); // \ 106 // report-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \ 107 // bugpath-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \ 108 // bugpath-note{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} 109 (void)ret; 110 } 111 112 void test_tolower_symbolic(int x) { 113 int ret = tolower(x); 114 (void)ret; 115 116 clang_analyzer_eval(EOF <= x && x <= 255); // \ 117 // report-warning{{TRUE}} \ 118 // bugpath-warning{{TRUE}} \ 119 // bugpath-note{{TRUE}} \ 120 // bugpath-note{{Left side of '&&' is true}} \ 121 // bugpath-note{{'x' is <= 255}} 122 } 123 124 void test_tolower_symbolic2(int x) { 125 if (x > 255) { // \ 126 // bugpath-note{{Assuming 'x' is > 255}} \ 127 // bugpath-note{{Taking true branch}} 128 129 int ret = tolower(x); // \ 130 // report-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \ 131 // bugpath-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \ 132 // bugpath-note{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} 133 134 (void)ret; 135 } 136 } 137 138 int toascii(int); 139 140 void test_toascii_concrete(int v) { 141 int ret = toascii(256); // \ 142 // report-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \ 143 // bugpath-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \ 144 // bugpath-note{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} 145 (void)ret; 146 } 147 148 void test_toascii_symbolic(int x) { 149 int ret = toascii(x); 150 (void)ret; 151 152 clang_analyzer_eval(EOF <= x && x <= 255); // \ 153 // report-warning{{TRUE}} \ 154 // bugpath-warning{{TRUE}} \ 155 // bugpath-note{{TRUE}} \ 156 // bugpath-note{{Left side of '&&' is true}} \ 157 // bugpath-note{{'x' is <= 255}} 158 } 159 160 void test_toascii_symbolic2(int x) { 161 if (x > 255) { // \ 162 // bugpath-note{{Assuming 'x' is > 255}} \ 163 // bugpath-note{{Taking true branch}} 164 165 int ret = toascii(x); // \ 166 // report-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \ 167 // bugpath-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \ 168 // bugpath-note{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} 169 170 (void)ret; 171 } 172 } 173 174 typedef struct FILE FILE; 175 typedef typeof(sizeof(int)) size_t; 176 size_t fread(void *restrict, size_t, size_t, FILE *restrict); 177 void test_notnull_concrete(FILE *fp) { 178 fread(0, sizeof(int), 10, fp); // \ 179 // report-warning{{The 1st argument to 'fread' should not be NULL}} \ 180 // bugpath-warning{{The 1st argument to 'fread' should not be NULL}} \ 181 // bugpath-note{{The 1st argument to 'fread' should not be NULL}} 182 } 183 void test_notnull_symbolic(FILE *fp, int *buf) { 184 fread(buf, sizeof(int), 10, fp); 185 clang_analyzer_eval(buf != 0); // \ 186 // report-warning{{TRUE}} \ 187 // bugpath-warning{{TRUE}} \ 188 // bugpath-note{{TRUE}} \ 189 // bugpath-note{{'buf' is not equal to null}} 190 } 191 void test_notnull_symbolic2(FILE *fp, int *buf) { 192 if (!buf) // bugpath-note{{Assuming 'buf' is null}} \ 193 // bugpath-note{{Taking true branch}} 194 fread(buf, sizeof(int), 10, fp); // \ 195 // report-warning{{The 1st argument to 'fread' should not be NULL}} \ 196 // bugpath-warning{{The 1st argument to 'fread' should not be NULL}} \ 197 // bugpath-note{{The 1st argument to 'fread' should not be NULL}} 198 } 199 void test_no_node_after_bug(FILE *fp, size_t size, size_t n, void *buf) { 200 if (fp) // \ 201 // bugpath-note{{Assuming 'fp' is null}} \ 202 // bugpath-note{{Taking false branch}} 203 return; 204 size_t ret = fread(buf, size, n, fp); // \ 205 // report-warning{{The 4th argument to 'fread' should not be NULL}} \ 206 // bugpath-warning{{The 4th argument to 'fread' should not be NULL}} \ 207 // bugpath-note{{The 4th argument to 'fread' should not be NULL}} 208 clang_analyzer_warnIfReached(); // not reachable 209 } 210 211 typedef __WCHAR_TYPE__ wchar_t; 212 // This is one test case for the ARR38-C SEI-CERT rule. 213 void ARR38_C_F(FILE *file) { 214 enum { BUFFER_SIZE = 1024 }; 215 wchar_t wbuf[BUFFER_SIZE]; // bugpath-note{{'wbuf' initialized here}} 216 217 const size_t size = sizeof(*wbuf); // bugpath-note{{'size' initialized to}} 218 const size_t nitems = sizeof(wbuf); // bugpath-note{{'nitems' initialized to}} 219 220 // The 3rd parameter should be the number of elements to read, not 221 // the size in bytes. 222 fread(wbuf, size, nitems, file); // \ 223 // report-warning{{The size of the 1st argument to 'fread' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \ 224 // bugpath-warning{{The size of the 1st argument to 'fread' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \ 225 // bugpath-note{{The size of the 1st argument to 'fread' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} 226 } 227 228 int __two_constrained_args(int, int); 229 void test_constraints_on_multiple_args(int x, int y) { 230 // State split should not happen here. I.e. x == 1 should not be evaluated 231 // FALSE. 232 __two_constrained_args(x, y); 233 //NOTE! Because of the second `clang_analyzer_eval` call we have two bug 234 clang_analyzer_eval(x == 1); // \ 235 // report-warning{{TRUE}} \ 236 // bugpath-warning{{TRUE}} \ 237 // bugpath-note{{TRUE}} 238 clang_analyzer_eval(y == 1); // \ 239 // report-warning{{TRUE}} \ 240 // bugpath-warning{{TRUE}} \ 241 // bugpath-note{{TRUE}} 242 } 243 244 int __arg_constrained_twice(int); 245 void test_multiple_constraints_on_same_arg(int x) { 246 __arg_constrained_twice(x); 247 clang_analyzer_eval(x < 1 || x > 2); // \ 248 // report-warning{{TRUE}} \ 249 // bugpath-warning{{TRUE}} \ 250 // bugpath-note{{TRUE}} \ 251 // bugpath-note{{Assuming 'x' is < 1}} \ 252 // bugpath-note{{Left side of '||' is true}} 253 } 254 255 int __variadic(void *stream, const char *format, ...); 256 void test_arg_constraint_on_variadic_fun(void) { 257 __variadic(0, "%d%d", 1, 2); // \ 258 // report-warning{{The 1st argument to '__variadic' should not be NULL}} \ 259 // bugpath-warning{{The 1st argument to '__variadic' should not be NULL}} \ 260 // bugpath-note{{The 1st argument to '__variadic' should not be NULL}} 261 } 262 263 int __buf_size_arg_constraint(const void *, size_t); 264 void test_buf_size_concrete(void) { 265 char buf[3]; // bugpath-note{{'buf' initialized here}} 266 __buf_size_arg_constraint(buf, 4); // \ 267 // report-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}} \ 268 // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}} \ 269 // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}} 270 } 271 void test_buf_size_symbolic(int s) { 272 char buf[3]; 273 __buf_size_arg_constraint(buf, s); 274 clang_analyzer_eval(s <= 3); // \ 275 // report-warning{{TRUE}} \ 276 // bugpath-warning{{TRUE}} \ 277 // bugpath-note{{TRUE}} \ 278 // bugpath-note{{'s' is <= 3}} 279 } 280 void test_buf_size_symbolic_and_offset(int s) { 281 char buf[3]; 282 __buf_size_arg_constraint(buf + 1, s); 283 clang_analyzer_eval(s <= 2); // \ 284 // report-warning{{TRUE}} \ 285 // bugpath-warning{{TRUE}} \ 286 // bugpath-note{{TRUE}} \ 287 // bugpath-note{{'s' is <= 2}} 288 } 289 290 int __buf_size_arg_constraint_mul(const void *, size_t, size_t); 291 void test_buf_size_concrete_with_multiplication(void) { 292 short buf[3]; // bugpath-note{{'buf' initialized here}} 293 __buf_size_arg_constraint_mul(buf, 4, sizeof(short)); // \ 294 // report-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \ 295 // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \ 296 // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} 297 } 298 void test_buf_size_symbolic_with_multiplication(size_t s) { 299 short buf[3]; 300 __buf_size_arg_constraint_mul(buf, s, sizeof(short)); 301 clang_analyzer_eval(s * sizeof(short) <= 6); // \ 302 // report-warning{{TRUE}} \ 303 // bugpath-warning{{TRUE}} \ 304 // bugpath-note{{TRUE}} 305 } 306 void test_buf_size_symbolic_and_offset_with_multiplication(size_t s) { 307 short buf[3]; 308 __buf_size_arg_constraint_mul(buf + 1, s, sizeof(short)); 309 clang_analyzer_eval(s * sizeof(short) <= 4); // \ 310 // report-warning{{TRUE}} \ 311 // bugpath-warning{{TRUE}} \ 312 // bugpath-note{{TRUE}} 313 } 314 315 // The minimum buffer size for this function is set to 10. 316 int __buf_size_arg_constraint_concrete(const void *); 317 void test_min_buf_size(void) { 318 char buf[9];// bugpath-note{{'buf' initialized here}} 319 __buf_size_arg_constraint_concrete(buf); // \ 320 // report-warning{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}} \ 321 // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}} \ 322 // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}} 323 } 324