Print this page
smatch: check libld_* allocation functions
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"
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
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 +static struct allocator illumos_user_allocator_table[] = {
30 + {"libld_malloc", 0},
31 + {"libld_realloc", 1},
32 +};
33 +
29 34 static struct allocator generic_allocator_table[] = {
30 35 {"malloc", 0},
31 36 {"memdup", 1},
32 37 {"realloc", 1},
33 38 };
34 39
35 40 static struct allocator kernel_allocator_table[] = {
36 41 {"kmalloc", 0},
37 42 {"kzalloc", 0},
38 43 {"vmalloc", 0},
39 44 {"__vmalloc", 0},
40 45 {"vzalloc", 0},
41 46 {"sock_kmalloc", 1},
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
42 47 {"kmemdup", 1},
43 48 {"kmemdup_user", 1},
44 49 {"dma_alloc_attrs", 1},
45 50 {"pci_alloc_consistent", 1},
46 51 {"pci_alloc_coherent", 1},
47 52 {"devm_kmalloc", 1},
48 53 {"devm_kzalloc", 1},
49 54 {"krealloc", 1},
50 55 };
51 56
52 -static struct allocator calloc_table[] = {
57 +static struct allocator illumos_user_calloc_table[] = {
58 + {"libld_calloc", 0, 1},
53 59 {"calloc", 0, 1},
54 60 {"kcalloc", 0, 1},
55 61 {"kmalloc_array", 0, 1},
56 62 {"devm_kcalloc", 1, 2},
57 63 };
58 64
65 +static struct allocator generic_calloc_table[] = {
66 + {"calloc", 0, 1},
67 +};
68 +
69 +static struct allocator kernel_calloc_table[] = {
70 + {"kcalloc", 0, 1},
71 + {"kmalloc_array", 0, 1},
72 + {"devm_kcalloc", 1, 2},
73 +};
74 +
59 75 static int bytes_per_element(struct expression *expr)
60 76 {
61 77 struct symbol *type;
62 78
63 79 type = get_type(expr);
64 80 if (!type)
65 81 return 0;
66 82
67 83 if (type->type != SYM_PTR && type->type != SYM_ARRAY)
68 84 return 0;
69 85
70 86 type = get_base_type(type);
71 87 return type_bytes(type);
72 88 }
73 89
74 90 static void save_constraint_required(struct expression *pointer, int op, struct expression *constraint)
75 91 {
76 92 char *data, *limit;
77 93
78 94 data = get_constraint_str(pointer);
79 95 if (!data)
80 96 return;
81 97
82 98 limit = get_constraint_str(constraint);
83 99 if (!limit) {
84 100 // FIXME deal with <= also
85 101 if (op == '<')
86 102 set_state_expr(my_id, constraint, alloc_state_expr(pointer));
87 103 goto free_data;
88 104 }
89 105
90 106 sql_save_constraint_required(data, op, limit);
91 107
92 108 free_string(limit);
93 109 free_data:
94 110 free_string(data);
95 111 }
96 112
97 113 static int handle_zero_size_arrays(struct expression *pointer, struct expression *size)
98 114 {
99 115 struct expression *left, *right;
100 116 struct symbol *type, *array, *array_type;
101 117 sval_t struct_size;
102 118 char *limit;
103 119 char data[128];
104 120
105 121 if (size->type != EXPR_BINOP || size->op != '+')
106 122 return 0;
107 123
108 124 type = get_type(pointer);
109 125 if (!type || type->type != SYM_PTR)
110 126 return 0;
111 127 type = get_real_base_type(type);
112 128 if (!type || !type->ident || type->type != SYM_STRUCT)
113 129 return 0;
114 130 if (!last_member_is_resizable(type))
115 131 return 0;
116 132 array = last_ptr_list((struct ptr_list *)type->symbol_list);
117 133 if (!array || !array->ident)
118 134 return 0;
119 135 array_type = get_real_base_type(array);
120 136 if (!array_type || array_type->type != SYM_ARRAY)
121 137 return 0;
122 138 array_type = get_real_base_type(array_type);
123 139
124 140 left = strip_expr(size->left);
125 141 right = strip_expr(size->right);
126 142
127 143 if (!get_implied_value(left, &struct_size))
128 144 return 0;
129 145 if (struct_size.value != type_bytes(type))
130 146 return 0;
131 147
132 148 if (right->type == EXPR_BINOP && right->op == '*') {
133 149 struct expression *mult_left, *mult_right;
134 150 sval_t sval;
135 151
136 152 mult_left = strip_expr(right->left);
137 153 mult_right = strip_expr(right->right);
138 154
139 155 if (get_implied_value(mult_left, &sval) &&
140 156 sval.value == type_bytes(array_type))
141 157 size = mult_right;
142 158 else if (get_implied_value(mult_right, &sval) &&
143 159 sval.value == type_bytes(array_type))
144 160 size = mult_left;
145 161 else
146 162 return 0;
147 163 }
148 164
149 165 snprintf(data, sizeof(data), "(struct %s)->%s", type->ident->name, array->ident->name);
150 166 limit = get_constraint_str(size);
151 167 if (!limit) {
152 168 set_state_expr(my_id, size, alloc_state_expr(
153 169 member_expression(deref_expression(pointer), '*', array->ident)));
154 170 return 1;
155 171 }
156 172
157 173 sql_save_constraint_required(data, '<', limit);
158 174
159 175 free_string(limit);
160 176 return 1;
161 177 }
162 178
163 179 static void match_alloc_helper(struct expression *pointer, struct expression *size, int recurse)
164 180 {
165 181 struct expression *size_orig, *tmp;
166 182 sval_t sval;
167 183 int cnt = 0;
168 184
169 185 pointer = strip_expr(pointer);
170 186 size = strip_expr(size);
171 187 if (!size || !pointer)
172 188 return;
173 189
174 190 size_orig = size;
175 191 if (recurse) {
176 192 while ((tmp = get_assigned_expr(size))) {
177 193 size = strip_expr(tmp);
178 194 if (cnt++ > 5)
179 195 break;
180 196 }
181 197 if (size != size_orig) {
182 198 match_alloc_helper(pointer, size, 0);
183 199 size = size_orig;
184 200 }
185 201 }
186 202
187 203 if (handle_zero_size_arrays(pointer, size))
188 204 return;
189 205
190 206 if (size->type == EXPR_BINOP && size->op == '*') {
191 207 struct expression *mult_left, *mult_right;
192 208
193 209 mult_left = strip_expr(size->left);
194 210 mult_right = strip_expr(size->right);
195 211
196 212 if (get_implied_value(mult_left, &sval) &&
197 213 sval.value == bytes_per_element(pointer))
198 214 size = mult_right;
199 215 else if (get_implied_value(mult_right, &sval) &&
200 216 sval.value == bytes_per_element(pointer))
201 217 size = mult_left;
202 218 else
203 219 return;
204 220 }
205 221
206 222 if (size->type == EXPR_BINOP && size->op == '+' &&
207 223 get_implied_value(size->right, &sval) &&
208 224 sval.value == 1)
209 225 save_constraint_required(pointer, SPECIAL_LTE, size->left);
210 226 else
211 227 save_constraint_required(pointer, '<', size);
212 228 }
213 229
214 230 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
215 231 {
216 232 int size_arg = PTR_INT(_size_arg);
217 233 struct expression *call, *arg;
218 234
219 235 call = strip_expr(expr->right);
220 236 arg = get_argument_from_call_expr(call->args, size_arg);
221 237
222 238 match_alloc_helper(expr->left, arg, 1);
223 239 }
224 240
225 241 static void match_calloc(const char *fn, struct expression *expr, void *_start_arg)
226 242 {
227 243 struct expression *pointer, *call, *size;
228 244 struct expression *count = NULL;
229 245 int start_arg = PTR_INT(_start_arg);
230 246 sval_t sval;
231 247
232 248 pointer = strip_expr(expr->left);
233 249 call = strip_expr(expr->right);
234 250
235 251 size = get_argument_from_call_expr(call->args, start_arg);
236 252 if (get_implied_value(size, &sval) &&
237 253 sval.value == bytes_per_element(pointer))
238 254 count = get_argument_from_call_expr(call->args, start_arg + 1);
239 255 else {
240 256 size = get_argument_from_call_expr(call->args, start_arg + 1);
241 257 if (get_implied_value(size, &sval) &&
242 258 sval.value == bytes_per_element(pointer))
243 259 count = get_argument_from_call_expr(call->args, start_arg);
244 260 }
245 261
246 262 if (!count)
247 263 return;
248 264
249 265 save_constraint_required(pointer, '<', count);
250 266 }
251 267
252 268 static void add_allocation_function(const char *func, void *call_back, int param)
253 269 {
254 270 add_function_assign_hook(func, call_back, INT_PTR(param));
255 271 }
256 272
257 273 static void match_assign_size(struct expression *expr)
258 274 {
259 275 struct smatch_state *state;
260 276 char *data, *limit;
261 277
262 278 state = get_state_expr(my_id, expr->right);
263 279 if (!state || !state->data)
264 280 return;
265 281
266 282 data = get_constraint_str(state->data);
267 283 if (!data)
268 284 return;
269 285
270 286 limit = get_constraint_str(expr->left);
271 287 if (!limit)
272 288 goto free_data;
273 289
274 290 sql_save_constraint_required(data, '<', limit);
275 291
276 292 free_string(limit);
277 293 free_data:
278 294 free_string(data);
279 295 }
280 296
281 297 static void match_assign_has_buf_comparison(struct expression *expr)
282 298 {
283 299 struct expression *size;
284 300
285 301 if (expr->op != '=')
286 302 return;
287 303 if (expr->right->type == EXPR_CALL)
288 304 return;
289 305 size = get_size_variable(expr->right);
290 306 if (!size)
291 307 return;
292 308 match_alloc_helper(expr->left, size, 1);
293 309 }
294 310
295 311 static void match_assign_data(struct expression *expr)
296 312 {
297 313 struct expression *right, *arg, *tmp;
298 314 int i;
299 315 int size_arg;
300 316 int size_arg2 = -1;
301 317
302 318 if (expr->op != '=')
303 319 return;
304 320
305 321 /* Direct calls are handled else where (for now at least) */
306 322 tmp = get_assigned_expr(expr->right);
307 323 if (!tmp)
308 324 return;
309 325
310 326 right = strip_expr(tmp);
311 327 if (right->type != EXPR_CALL)
312 328 return;
313 329
314 330 if (right->fn->type != EXPR_SYMBOL ||
315 331 !right->fn->symbol ||
316 332 !right->fn->symbol->ident)
↓ open down ↓ |
248 lines elided |
↑ open up ↑ |
317 333 return;
318 334
319 335 for (i = 0; i < ARRAY_SIZE(generic_allocator_table); i++) {
320 336 if (strcmp(right->fn->symbol->ident->name,
321 337 generic_allocator_table[i].func) == 0) {
322 338 size_arg = generic_allocator_table[i].param;
323 339 goto found;
324 340 }
325 341 }
326 342
343 + for (i = 0; i < ARRAY_SIZE(generic_calloc_table); i++) {
344 + if (strcmp(right->fn->symbol->ident->name,
345 + generic_calloc_table[i].func) == 0) {
346 + size_arg = generic_calloc_table[i].param;
347 + size_arg2 = generic_calloc_table[i].param2;
348 + goto found;
349 + }
350 + }
351 +
352 + if (option_project == PROJ_ILLUMOS_USER) {
353 + if (strcmp(right->fn->symbol->ident->name,
354 + illumos_user_allocator_table[i].func) == 0) {
355 + size_arg = illumos_user_allocator_table[i].param;
356 + goto found;
357 + }
358 +
359 + for (i = 0; i < ARRAY_SIZE(illumos_user_calloc_table); i++) {
360 + if (strcmp(right->fn->symbol->ident->name,
361 + illumos_user_calloc_table[i].func) == 0) {
362 + size_arg = illumos_user_calloc_table[i].param;
363 + size_arg2 = illumos_user_calloc_table[i].param2;
364 + goto found;
365 + }
366 + }
367 + }
368 +
327 369 if (option_project != PROJ_KERNEL)
328 370 return;
329 371
330 372 for (i = 0; i < ARRAY_SIZE(kernel_allocator_table); i++) {
331 373 if (strcmp(right->fn->symbol->ident->name,
332 374 kernel_allocator_table[i].func) == 0) {
333 375 size_arg = kernel_allocator_table[i].param;
334 376 goto found;
335 377 }
336 378 }
337 379
338 - for (i = 0; i < ARRAY_SIZE(calloc_table); i++) {
380 + for (i = 0; i < ARRAY_SIZE(kernel_calloc_table); i++) {
339 381 if (strcmp(right->fn->symbol->ident->name,
340 - calloc_table[i].func) == 0) {
341 - size_arg = calloc_table[i].param;
342 - size_arg2 = calloc_table[i].param2;
382 + kernel_calloc_table[i].func) == 0) {
383 + size_arg = kernel_calloc_table[i].param;
384 + size_arg2 = kernel_calloc_table[i].param2;
343 385 goto found;
344 386 }
345 387 }
346 388
347 389 return;
348 390
349 391 found:
350 392 arg = get_argument_from_call_expr(right->args, size_arg);
351 393 match_alloc_helper(expr->left, arg, 1);
352 394 if (size_arg2 == -1)
353 395 return;
354 396 arg = get_argument_from_call_expr(right->args, size_arg2);
355 397 match_alloc_helper(expr->left, arg, 1);
356 398 }
357 399
358 400 static void match_assign_ARRAY_SIZE(struct expression *expr)
359 401 {
360 402 struct expression *array;
361 403 char *data, *limit;
362 404 const char *macro;
363 405
364 406 macro = get_macro_name(expr->right->pos);
365 407 if (!macro || strcmp(macro, "ARRAY_SIZE") != 0)
366 408 return;
367 409 array = strip_expr(expr->right);
368 410 if (array->type != EXPR_BINOP || array->op != '+')
369 411 return;
370 412 array = strip_expr(array->left);
371 413 if (array->type != EXPR_BINOP || array->op != '/')
372 414 return;
373 415 array = strip_expr(array->left);
374 416 if (array->type != EXPR_SIZEOF)
375 417 return;
376 418 array = strip_expr(array->cast_expression);
377 419 if (array->type != EXPR_PREOP || array->op != '*')
378 420 return;
379 421 array = strip_expr(array->unop);
380 422
381 423 data = get_constraint_str(array);
382 424 limit = get_constraint_str(expr->left);
383 425 if (!data || !limit)
384 426 goto free;
385 427
386 428 sql_save_constraint_required(data, '<', limit);
387 429
388 430 free:
389 431 free_string(data);
390 432 free_string(limit);
391 433 }
392 434
393 435 static void match_assign_buf_comparison(struct expression *expr)
394 436 {
395 437 struct expression *pointer;
396 438
397 439 if (expr->op != '=')
398 440 return;
399 441 pointer = get_array_variable(expr->right);
400 442 if (!pointer)
401 443 return;
402 444
403 445 match_alloc_helper(pointer, expr->right, 1);
404 446 }
405 447
406 448 static int constraint_found(void *_found, int argc, char **argv, char **azColName)
407 449 {
408 450 int *found = _found;
409 451
410 452 *found = 1;
411 453 return 0;
412 454 }
413 455
414 456 static int has_constraint(struct expression *expr, const char *constraint)
415 457 {
416 458 int found = 0;
417 459
418 460 if (get_state_expr(my_id, expr))
419 461 return 1;
420 462
421 463 run_sql(constraint_found, &found,
422 464 "select data from constraints_required where bound = '%q' limit 1",
423 465 escape_newlines(constraint));
424 466
425 467 return found;
426 468 }
427 469
428 470 static void match_assign_constraint(struct expression *expr)
429 471 {
430 472 struct symbol *type;
431 473 char *left, *right;
432 474
433 475 if (expr->op != '=')
434 476 return;
435 477
436 478 type = get_type(expr->left);
437 479 if (!type || type->type != SYM_BASETYPE)
438 480 return;
439 481
440 482 left = get_constraint_str(expr->left);
441 483 if (!left)
442 484 return;
443 485 right = get_constraint_str(expr->right);
444 486 if (!right)
445 487 goto free;
446 488 if (!has_constraint(expr->right, right))
447 489 return;
448 490 sql_copy_constraint_required(left, right);
449 491 free:
450 492 free_string(right);
451 493 free_string(left);
452 494 }
453 495
454 496 void register_constraints_required(int id)
455 497 {
456 498 my_id = id;
457 499
458 500 add_hook(&match_assign_size, ASSIGNMENT_HOOK);
459 501 add_hook(&match_assign_data, ASSIGNMENT_HOOK);
↓ open down ↓ |
107 lines elided |
↑ open up ↑ |
460 502 add_hook(&match_assign_has_buf_comparison, ASSIGNMENT_HOOK);
461 503
462 504 add_hook(&match_assign_ARRAY_SIZE, ASSIGNMENT_HOOK);
463 505 add_hook(&match_assign_ARRAY_SIZE, GLOBAL_ASSIGNMENT_HOOK);
464 506 add_hook(&match_assign_buf_comparison, ASSIGNMENT_HOOK);
465 507 add_hook(&match_assign_constraint, ASSIGNMENT_HOOK);
466 508
467 509 add_allocation_function("malloc", &match_alloc, 0);
468 510 add_allocation_function("memdup", &match_alloc, 1);
469 511 add_allocation_function("realloc", &match_alloc, 1);
470 - add_allocation_function("realloc", &match_calloc, 0);
512 + add_allocation_function("calloc", &match_calloc, 0);
513 + if (option_project == PROJ_ILLUMOS_USER) {
514 + add_allocation_function("libld_malloc", &match_alloc, 0);
515 + add_allocation_function("libld_realloc", &match_alloc, 1);
516 + add_allocation_function("libld_calloc", &match_calloc, 0);
517 + }
471 518 if (option_project == PROJ_KERNEL) {
472 519 add_allocation_function("kmalloc", &match_alloc, 0);
473 520 add_allocation_function("kzalloc", &match_alloc, 0);
474 521 add_allocation_function("vmalloc", &match_alloc, 0);
475 522 add_allocation_function("__vmalloc", &match_alloc, 0);
476 523 add_allocation_function("vzalloc", &match_alloc, 0);
477 524 add_allocation_function("sock_kmalloc", &match_alloc, 1);
478 525 add_allocation_function("kmemdup", &match_alloc, 1);
479 526 add_allocation_function("kmemdup_user", &match_alloc, 1);
480 527 add_allocation_function("dma_alloc_attrs", &match_alloc, 1);
481 528 add_allocation_function("pci_alloc_consistent", &match_alloc, 1);
482 529 add_allocation_function("pci_alloc_coherent", &match_alloc, 1);
483 530 add_allocation_function("devm_kmalloc", &match_alloc, 1);
484 531 add_allocation_function("devm_kzalloc", &match_alloc, 1);
485 532 add_allocation_function("kcalloc", &match_calloc, 0);
486 533 add_allocation_function("kmalloc_array", &match_calloc, 0);
487 534 add_allocation_function("devm_kcalloc", &match_calloc, 1);
488 535 add_allocation_function("krealloc", &match_alloc, 1);
489 536 }
490 537 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX