Print this page
11506 smatch resync
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/smatch_constraints_required.c
+++ new/usr/src/tools/smatch/src/smatch_constraints_required.c
1 1 /*
2 2 * Copyright (C) 2017 Oracle.
3 3 *
4 4 * This program is free software; you can redistribute it and/or
5 5 * modify it under the terms of the GNU General Public License
6 6 * as published by the Free Software Foundation; either version 2
7 7 * of the License, or (at your option) any later version.
8 8 *
9 9 * This program is distributed in the hope that it will be useful,
10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 * GNU General Public License for more details.
13 13 *
14 14 * You should have received a copy of the GNU General Public License
15 15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
16 16 */
17 17
18 18 #include "smatch.h"
19 19 #include "smatch_extra.h"
20 20
21 21 static int my_id;
22 22
23 23 struct allocator {
24 24 const char *func;
25 25 int param;
26 26 int param2;
27 27 };
28 28
29 29 static struct allocator generic_allocator_table[] = {
30 30 {"malloc", 0},
31 31 {"memdup", 1},
32 32 {"realloc", 1},
33 33 };
34 34
35 35 static struct allocator kernel_allocator_table[] = {
36 36 {"kmalloc", 0},
37 37 {"kzalloc", 0},
38 38 {"vmalloc", 0},
39 39 {"__vmalloc", 0},
40 40 {"vzalloc", 0},
41 41 {"sock_kmalloc", 1},
42 42 {"kmemdup", 1},
43 43 {"kmemdup_user", 1},
44 44 {"dma_alloc_attrs", 1},
45 45 {"pci_alloc_consistent", 1},
46 46 {"pci_alloc_coherent", 1},
47 47 {"devm_kmalloc", 1},
48 48 {"devm_kzalloc", 1},
49 49 {"krealloc", 1},
50 50 };
51 51
52 52 static struct allocator calloc_table[] = {
53 53 {"calloc", 0, 1},
54 54 {"kcalloc", 0, 1},
55 55 {"kmalloc_array", 0, 1},
56 56 {"devm_kcalloc", 1, 2},
57 57 };
58 58
59 59 static int bytes_per_element(struct expression *expr)
60 60 {
61 61 struct symbol *type;
62 62
63 63 type = get_type(expr);
64 64 if (!type)
65 65 return 0;
66 66
67 67 if (type->type != SYM_PTR && type->type != SYM_ARRAY)
68 68 return 0;
69 69
70 70 type = get_base_type(type);
71 71 return type_bytes(type);
72 72 }
73 73
74 74 static void save_constraint_required(struct expression *pointer, int op, struct expression *constraint)
75 75 {
76 76 char *data, *limit;
77 77
78 78 data = get_constraint_str(pointer);
79 79 if (!data)
80 80 return;
81 81
82 82 limit = get_constraint_str(constraint);
83 83 if (!limit) {
84 84 // FIXME deal with <= also
85 85 if (op == '<')
86 86 set_state_expr(my_id, constraint, alloc_state_expr(pointer));
87 87 goto free_data;
88 88 }
89 89
90 90 sql_save_constraint_required(data, op, limit);
91 91
92 92 free_string(limit);
93 93 free_data:
94 94 free_string(data);
95 95 }
96 96
97 97 static int handle_zero_size_arrays(struct expression *pointer, struct expression *size)
98 98 {
99 99 struct expression *left, *right;
100 100 struct symbol *type, *array, *array_type;
101 101 sval_t struct_size;
102 102 char *limit;
103 103 char data[128];
104 104
105 105 if (size->type != EXPR_BINOP || size->op != '+')
106 106 return 0;
107 107
108 108 type = get_type(pointer);
109 109 if (!type || type->type != SYM_PTR)
110 110 return 0;
111 111 type = get_real_base_type(type);
112 112 if (!type || !type->ident || type->type != SYM_STRUCT)
113 113 return 0;
114 114 if (!last_member_is_resizable(type))
115 115 return 0;
116 116 array = last_ptr_list((struct ptr_list *)type->symbol_list);
117 117 if (!array || !array->ident)
118 118 return 0;
119 119 array_type = get_real_base_type(array);
120 120 if (!array_type || array_type->type != SYM_ARRAY)
121 121 return 0;
122 122 array_type = get_real_base_type(array_type);
123 123
124 124 left = strip_expr(size->left);
125 125 right = strip_expr(size->right);
126 126
127 127 if (!get_implied_value(left, &struct_size))
128 128 return 0;
129 129 if (struct_size.value != type_bytes(type))
130 130 return 0;
131 131
132 132 if (right->type == EXPR_BINOP && right->op == '*') {
133 133 struct expression *mult_left, *mult_right;
134 134 sval_t sval;
135 135
136 136 mult_left = strip_expr(right->left);
137 137 mult_right = strip_expr(right->right);
138 138
139 139 if (get_implied_value(mult_left, &sval) &&
140 140 sval.value == type_bytes(array_type))
141 141 size = mult_right;
142 142 else if (get_implied_value(mult_right, &sval) &&
143 143 sval.value == type_bytes(array_type))
144 144 size = mult_left;
145 145 else
146 146 return 0;
147 147 }
148 148
149 149 snprintf(data, sizeof(data), "(struct %s)->%s", type->ident->name, array->ident->name);
150 150 limit = get_constraint_str(size);
151 151 if (!limit) {
152 152 set_state_expr(my_id, size, alloc_state_expr(
153 153 member_expression(deref_expression(pointer), '*', array->ident)));
154 154 return 1;
155 155 }
156 156
157 157 sql_save_constraint_required(data, '<', limit);
158 158
159 159 free_string(limit);
160 160 return 1;
161 161 }
162 162
163 163 static void match_alloc_helper(struct expression *pointer, struct expression *size, int recurse)
164 164 {
165 165 struct expression *size_orig, *tmp;
166 166 sval_t sval;
167 167 int cnt = 0;
168 168
169 169 pointer = strip_expr(pointer);
170 170 size = strip_expr(size);
171 171 if (!size || !pointer)
172 172 return;
173 173
174 174 size_orig = size;
175 175 if (recurse) {
176 176 while ((tmp = get_assigned_expr(size))) {
177 177 size = strip_expr(tmp);
178 178 if (cnt++ > 5)
179 179 break;
180 180 }
181 181 if (size != size_orig) {
182 182 match_alloc_helper(pointer, size, 0);
183 183 size = size_orig;
184 184 }
185 185 }
186 186
187 187 if (handle_zero_size_arrays(pointer, size))
188 188 return;
189 189
190 190 if (size->type == EXPR_BINOP && size->op == '*') {
191 191 struct expression *mult_left, *mult_right;
192 192
193 193 mult_left = strip_expr(size->left);
194 194 mult_right = strip_expr(size->right);
195 195
196 196 if (get_implied_value(mult_left, &sval) &&
197 197 sval.value == bytes_per_element(pointer))
198 198 size = mult_right;
199 199 else if (get_implied_value(mult_right, &sval) &&
200 200 sval.value == bytes_per_element(pointer))
201 201 size = mult_left;
202 202 else
203 203 return;
204 204 }
205 205
206 206 if (size->type == EXPR_BINOP && size->op == '+' &&
207 207 get_implied_value(size->right, &sval) &&
208 208 sval.value == 1)
209 209 save_constraint_required(pointer, SPECIAL_LTE, size->left);
210 210 else
211 211 save_constraint_required(pointer, '<', size);
212 212 }
213 213
214 214 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
215 215 {
216 216 int size_arg = PTR_INT(_size_arg);
217 217 struct expression *call, *arg;
218 218
219 219 call = strip_expr(expr->right);
220 220 arg = get_argument_from_call_expr(call->args, size_arg);
221 221
222 222 match_alloc_helper(expr->left, arg, 1);
223 223 }
224 224
225 225 static void match_calloc(const char *fn, struct expression *expr, void *_start_arg)
226 226 {
227 227 struct expression *pointer, *call, *size;
228 228 struct expression *count = NULL;
229 229 int start_arg = PTR_INT(_start_arg);
230 230 sval_t sval;
231 231
232 232 pointer = strip_expr(expr->left);
233 233 call = strip_expr(expr->right);
234 234
235 235 size = get_argument_from_call_expr(call->args, start_arg);
236 236 if (get_implied_value(size, &sval) &&
237 237 sval.value == bytes_per_element(pointer))
238 238 count = get_argument_from_call_expr(call->args, start_arg + 1);
239 239 else {
240 240 size = get_argument_from_call_expr(call->args, start_arg + 1);
241 241 if (get_implied_value(size, &sval) &&
242 242 sval.value == bytes_per_element(pointer))
243 243 count = get_argument_from_call_expr(call->args, start_arg);
244 244 }
245 245
246 246 if (!count)
247 247 return;
248 248
249 249 save_constraint_required(pointer, '<', count);
250 250 }
251 251
252 252 static void add_allocation_function(const char *func, void *call_back, int param)
253 253 {
254 254 add_function_assign_hook(func, call_back, INT_PTR(param));
255 255 }
256 256
257 257 static void match_assign_size(struct expression *expr)
258 258 {
259 259 struct smatch_state *state;
260 260 char *data, *limit;
261 261
262 262 state = get_state_expr(my_id, expr->right);
263 263 if (!state || !state->data)
264 264 return;
265 265
266 266 data = get_constraint_str(state->data);
267 267 if (!data)
268 268 return;
269 269
270 270 limit = get_constraint_str(expr->left);
271 271 if (!limit)
272 272 goto free_data;
273 273
↓ open down ↓ |
273 lines elided |
↑ open up ↑ |
274 274 sql_save_constraint_required(data, '<', limit);
275 275
276 276 free_string(limit);
277 277 free_data:
278 278 free_string(data);
279 279 }
280 280
281 281 static void match_assign_has_buf_comparison(struct expression *expr)
282 282 {
283 283 struct expression *size;
284 + int limit_type;
284 285
285 286 if (expr->op != '=')
286 287 return;
287 288 if (expr->right->type == EXPR_CALL)
288 289 return;
289 - size = get_size_variable(expr->right);
290 + size = get_size_variable(expr->right, &limit_type);
290 291 if (!size)
291 292 return;
293 + if (limit_type != ELEM_COUNT)
294 + return;
292 295 match_alloc_helper(expr->left, size, 1);
293 296 }
294 297
295 298 static void match_assign_data(struct expression *expr)
296 299 {
297 300 struct expression *right, *arg, *tmp;
298 301 int i;
299 302 int size_arg;
300 303 int size_arg2 = -1;
301 304
302 305 if (expr->op != '=')
303 306 return;
304 307
305 308 /* Direct calls are handled else where (for now at least) */
306 309 tmp = get_assigned_expr(expr->right);
307 310 if (!tmp)
308 311 return;
309 312
310 313 right = strip_expr(tmp);
311 314 if (right->type != EXPR_CALL)
312 315 return;
313 316
314 317 if (right->fn->type != EXPR_SYMBOL ||
315 318 !right->fn->symbol ||
316 319 !right->fn->symbol->ident)
317 320 return;
318 321
319 322 for (i = 0; i < ARRAY_SIZE(generic_allocator_table); i++) {
320 323 if (strcmp(right->fn->symbol->ident->name,
321 324 generic_allocator_table[i].func) == 0) {
322 325 size_arg = generic_allocator_table[i].param;
323 326 goto found;
324 327 }
325 328 }
326 329
327 330 if (option_project != PROJ_KERNEL)
328 331 return;
329 332
330 333 for (i = 0; i < ARRAY_SIZE(kernel_allocator_table); i++) {
331 334 if (strcmp(right->fn->symbol->ident->name,
332 335 kernel_allocator_table[i].func) == 0) {
333 336 size_arg = kernel_allocator_table[i].param;
334 337 goto found;
335 338 }
336 339 }
337 340
338 341 for (i = 0; i < ARRAY_SIZE(calloc_table); i++) {
339 342 if (strcmp(right->fn->symbol->ident->name,
340 343 calloc_table[i].func) == 0) {
341 344 size_arg = calloc_table[i].param;
342 345 size_arg2 = calloc_table[i].param2;
343 346 goto found;
344 347 }
345 348 }
346 349
347 350 return;
348 351
349 352 found:
350 353 arg = get_argument_from_call_expr(right->args, size_arg);
351 354 match_alloc_helper(expr->left, arg, 1);
352 355 if (size_arg2 == -1)
353 356 return;
354 357 arg = get_argument_from_call_expr(right->args, size_arg2);
355 358 match_alloc_helper(expr->left, arg, 1);
356 359 }
357 360
358 361 static void match_assign_ARRAY_SIZE(struct expression *expr)
359 362 {
360 363 struct expression *array;
361 364 char *data, *limit;
362 365 const char *macro;
363 366
364 367 macro = get_macro_name(expr->right->pos);
365 368 if (!macro || strcmp(macro, "ARRAY_SIZE") != 0)
366 369 return;
367 370 array = strip_expr(expr->right);
368 371 if (array->type != EXPR_BINOP || array->op != '+')
369 372 return;
370 373 array = strip_expr(array->left);
371 374 if (array->type != EXPR_BINOP || array->op != '/')
372 375 return;
373 376 array = strip_expr(array->left);
374 377 if (array->type != EXPR_SIZEOF)
375 378 return;
376 379 array = strip_expr(array->cast_expression);
377 380 if (array->type != EXPR_PREOP || array->op != '*')
378 381 return;
379 382 array = strip_expr(array->unop);
380 383
381 384 data = get_constraint_str(array);
382 385 limit = get_constraint_str(expr->left);
383 386 if (!data || !limit)
384 387 goto free;
385 388
386 389 sql_save_constraint_required(data, '<', limit);
387 390
388 391 free:
389 392 free_string(data);
390 393 free_string(limit);
391 394 }
392 395
393 396 static void match_assign_buf_comparison(struct expression *expr)
394 397 {
395 398 struct expression *pointer;
396 399
397 400 if (expr->op != '=')
398 401 return;
399 402 pointer = get_array_variable(expr->right);
400 403 if (!pointer)
401 404 return;
402 405
403 406 match_alloc_helper(pointer, expr->right, 1);
404 407 }
405 408
406 409 static int constraint_found(void *_found, int argc, char **argv, char **azColName)
407 410 {
408 411 int *found = _found;
409 412
410 413 *found = 1;
411 414 return 0;
412 415 }
413 416
414 417 static int has_constraint(struct expression *expr, const char *constraint)
415 418 {
416 419 int found = 0;
417 420
418 421 if (get_state_expr(my_id, expr))
419 422 return 1;
420 423
421 424 run_sql(constraint_found, &found,
422 425 "select data from constraints_required where bound = '%q' limit 1",
423 426 escape_newlines(constraint));
424 427
425 428 return found;
426 429 }
427 430
428 431 static void match_assign_constraint(struct expression *expr)
429 432 {
430 433 struct symbol *type;
431 434 char *left, *right;
432 435
433 436 if (expr->op != '=')
434 437 return;
435 438
436 439 type = get_type(expr->left);
437 440 if (!type || type->type != SYM_BASETYPE)
438 441 return;
439 442
440 443 left = get_constraint_str(expr->left);
441 444 if (!left)
442 445 return;
443 446 right = get_constraint_str(expr->right);
444 447 if (!right)
445 448 goto free;
446 449 if (!has_constraint(expr->right, right))
447 450 return;
↓ open down ↓ |
146 lines elided |
↑ open up ↑ |
448 451 sql_copy_constraint_required(left, right);
449 452 free:
450 453 free_string(right);
451 454 free_string(left);
452 455 }
453 456
454 457 void register_constraints_required(int id)
455 458 {
456 459 my_id = id;
457 460
461 + set_dynamic_states(my_id);
458 462 add_hook(&match_assign_size, ASSIGNMENT_HOOK);
459 463 add_hook(&match_assign_data, ASSIGNMENT_HOOK);
460 464 add_hook(&match_assign_has_buf_comparison, ASSIGNMENT_HOOK);
461 465
462 466 add_hook(&match_assign_ARRAY_SIZE, ASSIGNMENT_HOOK);
463 467 add_hook(&match_assign_ARRAY_SIZE, GLOBAL_ASSIGNMENT_HOOK);
464 468 add_hook(&match_assign_buf_comparison, ASSIGNMENT_HOOK);
465 469 add_hook(&match_assign_constraint, ASSIGNMENT_HOOK);
466 470
467 471 add_allocation_function("malloc", &match_alloc, 0);
468 472 add_allocation_function("memdup", &match_alloc, 1);
469 473 add_allocation_function("realloc", &match_alloc, 1);
470 474 add_allocation_function("realloc", &match_calloc, 0);
471 475 if (option_project == PROJ_KERNEL) {
472 476 add_allocation_function("kmalloc", &match_alloc, 0);
473 477 add_allocation_function("kzalloc", &match_alloc, 0);
474 478 add_allocation_function("vmalloc", &match_alloc, 0);
475 479 add_allocation_function("__vmalloc", &match_alloc, 0);
476 480 add_allocation_function("vzalloc", &match_alloc, 0);
477 481 add_allocation_function("sock_kmalloc", &match_alloc, 1);
478 482 add_allocation_function("kmemdup", &match_alloc, 1);
479 483 add_allocation_function("kmemdup_user", &match_alloc, 1);
480 484 add_allocation_function("dma_alloc_attrs", &match_alloc, 1);
481 485 add_allocation_function("pci_alloc_consistent", &match_alloc, 1);
482 486 add_allocation_function("pci_alloc_coherent", &match_alloc, 1);
483 487 add_allocation_function("devm_kmalloc", &match_alloc, 1);
484 488 add_allocation_function("devm_kzalloc", &match_alloc, 1);
485 489 add_allocation_function("kcalloc", &match_calloc, 0);
486 490 add_allocation_function("kmalloc_array", &match_calloc, 0);
487 491 add_allocation_function("devm_kcalloc", &match_calloc, 1);
488 492 add_allocation_function("krealloc", &match_alloc, 1);
489 493 }
490 494 }
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX