Print this page
12724 update smatch to 0.6.1-rc1-il-5
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/tools/smatch/src/smatch_struct_assignment.c
+++ new/usr/src/tools/smatch/src/smatch_struct_assignment.c
1 1 /*
2 2 * Copyright (C) 2014 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 /*
19 19 * This file started out by saying that if you have:
20 20 *
21 21 * struct foo one, two;
22 22 * ...
23 23 * one = two;
24 24 *
25 25 * That's equivalent to saying:
26 26 *
27 27 * one.x = two.x;
28 28 * one.y = two.y;
29 29 *
30 30 * Turning an assignment like that into a bunch of small fake assignments is
31 31 * really useful.
32 32 *
33 33 * The call to memcpy(&one, &two, sizeof(foo)); is the same as "one = two;" so
34 34 * we can re-use the code. And we may as well use it for memset() too.
35 35 * Assigning pointers is almost the same:
36 36 *
37 37 * p1 = p2;
38 38 *
39 39 * Is the same as:
40 40 *
41 41 * p1->x = p2->x;
42 42 * p1->y = p2->y;
43 43 *
44 44 * The problem is that you can go a bit crazy with pointers to pointers.
45 45 *
46 46 * p1->x->y->z->one->two->three = p2->x->y->z->one->two->three;
47 47 *
48 48 * I don't have a proper solution for this problem right now. I just copy one
49 49 * level and don't nest. It should handle limitted nesting but intelligently.
50 50 *
51 51 * The other thing is that you end up with a lot of garbage assignments where
52 52 * we record "x could be anything. x->y could be anything. x->y->z->a->b->c
53 53 * could *also* be anything!". There should be a better way to filter this
54 54 * useless information.
55 55 *
56 56 */
57 57
58 58 #include "scope.h"
59 59 #include "smatch.h"
60 60 #include "smatch_slist.h"
61 61 #include "smatch_extra.h"
62 62
63 63 enum {
64 64 COPY_NORMAL,
65 65 COPY_MEMCPY,
66 66 COPY_MEMSET,
67 67 };
68 68
69 69 static struct symbol *get_struct_type(struct expression *expr)
70 70 {
71 71 struct symbol *type;
72 72
73 73 type = get_type(expr);
74 74 if (!type)
75 75 return NULL;
76 76 if (type->type == SYM_PTR) {
77 77 type = get_real_base_type(type);
78 78 if (!type)
79 79 return NULL;
80 80 }
81 81 if (type->type == SYM_STRUCT)
82 82 return type;
83 83 if (type->type == SYM_UNION)
84 84 return type;
85 85 return NULL;
86 86 }
87 87
88 88 static struct expression *get_right_base_expr(struct symbol *left_type, struct expression *right)
89 89 {
90 90 struct symbol *struct_type;
91 91
92 92 if (!right)
93 93 return NULL;
94 94
95 95 struct_type = get_struct_type(right);
96 96 if (!struct_type)
97 97 return NULL;
98 98 if (struct_type != left_type)
99 99 return NULL;
100 100
101 101 if (right->type == EXPR_PREOP && right->op == '&')
102 102 right = strip_expr(right->unop);
103 103
104 104 if (right->type == EXPR_CALL)
105 105 return NULL;
106 106
107 107 if (is_pointer(right))
108 108 right = deref_expression(right);
109 109
110 110 return right;
111 111 }
112 112
113 113 static struct expression *remove_addr(struct expression *expr)
114 114 {
115 115 struct symbol *type;
116 116
117 117 expr = strip_expr(expr);
118 118 if (!expr)
119 119 return NULL;
120 120
121 121 if (expr->type == EXPR_PREOP && expr->op == '&')
122 122 return strip_expr(expr->unop);
123 123 type = get_type(expr);
124 124 if (!type)
125 125 return expr;
126 126 if (type->type != SYM_PTR && type->type != SYM_ARRAY)
127 127 return expr;
128 128
129 129 return deref_expression(expr);
130 130 }
131 131
132 132 static struct expression *faked_expression;
133 133 struct expression *get_faked_expression(void)
134 134 {
135 135 if (!__in_fake_assign)
136 136 return NULL;
137 137 return faked_expression;
138 138 }
139 139
140 140 static void split_fake_expr(struct expression *expr)
141 141 {
142 142 __in_fake_assign++;
143 143 __in_fake_struct_assign++;
↓ open down ↓ |
143 lines elided |
↑ open up ↑ |
144 144 __split_expr(expr);
145 145 __in_fake_struct_assign--;
146 146 __in_fake_assign--;
147 147 }
148 148
149 149 static void handle_non_struct_assignments(struct expression *left, struct expression *right)
150 150 {
151 151 struct symbol *type;
152 152 struct expression *assign;
153 153
154 + while (right && right->type == EXPR_ASSIGNMENT)
155 + right = strip_parens(right->left);
156 +
154 157 type = get_type(left);
155 158 if (!type)
156 159 return;
157 160 if (type->type == SYM_PTR) {
158 161 left = deref_expression(left);
159 162 if (right)
160 163 right = deref_expression(right);
161 164 else
162 165 right = unknown_value_expression(left);
163 166 assign = assign_expression(left, '=', right);
164 167 split_fake_expr(assign);
165 168 return;
166 169 }
167 170 if (type->type != SYM_BASETYPE)
168 171 return;
169 172 right = strip_expr(right);
170 173 type = get_type(right);
171 174 if (!right || !type || type->type == SYM_ARRAY)
172 175 right = unknown_value_expression(left);
173 176 assign = assign_expression(left, '=', right);
174 177 split_fake_expr(assign);
175 178 }
176 179
177 180 static void set_inner_struct_members(int mode, struct expression *faked, struct expression *left, struct expression *right, struct symbol *member)
178 181 {
179 182 struct expression *left_member;
180 183 struct expression *right_member = NULL; /* silence GCC */
181 184 struct expression *assign;
182 185 struct symbol *base = get_real_base_type(member);
183 186 struct symbol *tmp;
184 187
185 188 if (member->ident) {
186 189 left = member_expression(left, '.', member->ident);
187 190 if (mode != COPY_MEMSET && right)
188 191 right = member_expression(right, '.', member->ident);
189 192 }
190 193
191 194 FOR_EACH_PTR(base->symbol_list, tmp) {
192 195 struct symbol *type;
193 196
194 197 type = get_real_base_type(tmp);
195 198 if (!type)
196 199 continue;
197 200
198 201 if (type->type == SYM_ARRAY)
199 202 continue;
200 203 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
201 204 set_inner_struct_members(mode, faked, left, right, tmp);
202 205 continue;
203 206 }
204 207 if (!tmp->ident)
205 208 continue;
206 209
207 210 left_member = member_expression(left, '.', tmp->ident);
208 211
209 212 switch (mode) {
210 213 case COPY_NORMAL:
211 214 case COPY_MEMCPY:
212 215 if (right)
213 216 right_member = member_expression(right, '.', tmp->ident);
214 217 else
215 218 right_member = unknown_value_expression(left_member);
216 219 break;
217 220 case COPY_MEMSET:
218 221 right_member = right;
219 222 break;
220 223 }
221 224
222 225 assign = assign_expression(left_member, '=', right_member);
223 226 split_fake_expr(assign);
224 227 } END_FOR_EACH_PTR(tmp);
225 228 }
226 229
↓ open down ↓ |
63 lines elided |
↑ open up ↑ |
227 230 static void __struct_members_copy(int mode, struct expression *faked,
228 231 struct expression *left,
229 232 struct expression *right)
230 233 {
231 234 struct symbol *struct_type, *tmp, *type;
232 235 struct expression *left_member;
233 236 struct expression *right_member;
234 237 struct expression *assign;
235 238 int op = '.';
236 239
237 -
238 240 if (__in_fake_assign)
239 241 return;
240 242 faked_expression = faked;
241 243
242 244 left = strip_expr(left);
243 245 right = strip_expr(right);
244 246
247 + if (left->type == EXPR_PREOP && left->op == '*' && is_pointer(left))
248 + left = preop_expression(left, '(');
249 +
245 250 struct_type = get_struct_type(left);
246 251 if (!struct_type) {
247 252 /*
248 253 * This is not a struct assignment obviously. But this is where
249 254 * memcpy() is handled so it feels like a good place to add this
250 255 * code.
251 256 */
252 257 handle_non_struct_assignments(left, right);
253 258 goto done;
254 259 }
255 260
256 261 if (is_pointer(left)) {
257 262 left = deref_expression(left);
258 263 op = '*';
259 264 }
260 265 if (mode != COPY_MEMSET)
261 266 right = get_right_base_expr(struct_type, right);
262 267
263 268 FOR_EACH_PTR(struct_type->symbol_list, tmp) {
264 269 type = get_real_base_type(tmp);
265 270 if (!type)
266 271 continue;
267 272 if (type->type == SYM_ARRAY)
268 273 continue;
269 274
270 275 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
271 276 set_inner_struct_members(mode, faked, left, right, tmp);
272 277 continue;
273 278 }
274 279
275 280 if (!tmp->ident)
276 281 continue;
277 282
278 283 left_member = member_expression(left, op, tmp->ident);
279 284 right_member = NULL;
280 285
281 286 switch (mode) {
282 287 case COPY_NORMAL:
283 288 case COPY_MEMCPY:
284 289 if (right)
285 290 right_member = member_expression(right, op, tmp->ident);
286 291 else
287 292 right_member = unknown_value_expression(left_member);
288 293 break;
289 294 case COPY_MEMSET:
290 295 right_member = right;
291 296 break;
292 297 }
293 298 if (!right_member) {
294 299 sm_perror("No right member");
295 300 continue;
296 301 }
297 302 assign = assign_expression(left_member, '=', right_member);
298 303 split_fake_expr(assign);
299 304 } END_FOR_EACH_PTR(tmp);
300 305
301 306 done:
302 307 faked_expression = NULL;
303 308 }
304 309
305 310 static int returns_zeroed_mem(struct expression *expr)
306 311 {
307 312 char *fn;
308 313
309 314 if (expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL)
310 315 return 0;
311 316 fn = expr_to_var(expr->fn);
312 317 if (!fn)
313 318 return 0;
314 319 if (strcmp(fn, "kcalloc") == 0)
315 320 return 1;
316 321 if (option_project == PROJ_KERNEL && strstr(fn, "zalloc"))
317 322 return 1;
318 323 return 0;
319 324 }
320 325
321 326 static int copy_containter_states(struct expression *left, struct expression *right, int offset)
322 327 {
323 328 char *left_name = NULL, *right_name = NULL;
324 329 struct symbol *left_sym, *right_sym;
325 330 struct sm_state *sm, *new_sm;
326 331 int ret = 0;
327 332 int len;
328 333 char buf[64];
329 334 char new_name[128];
330 335
331 336 right_name = expr_to_var_sym(right, &right_sym);
332 337 if (!right_name || !right_sym)
333 338 goto free;
334 339 left_name = expr_to_var_sym(left, &left_sym);
335 340 if (!left_name || !left_sym)
336 341 goto free;
337 342
338 343 len = snprintf(buf, sizeof(buf), "%s(-%d)", right_name, offset);
339 344 if (len >= sizeof(buf))
340 345 goto free;
341 346
342 347 FOR_EACH_SM(__get_cur_stree(), sm) {
343 348 if (sm->sym != right_sym)
344 349 continue;
345 350 if (strncmp(sm->name, buf, len) != 0)
346 351 continue;
347 352 snprintf(new_name, sizeof(new_name), "%s%s", left_name, sm->name + len);
348 353 new_sm = clone_sm(sm);
349 354 new_sm->name = alloc_sname(new_name);
350 355 new_sm->sym = left_sym;
351 356 __set_sm(new_sm);
352 357 ret = 1;
353 358 } END_FOR_EACH_SM(sm);
354 359 free:
355 360 free_string(left_name);
356 361 free_string(right_name);
357 362 return ret;
358 363 }
359 364
360 365 static int handle_param_offsets(struct expression *expr)
361 366 {
362 367 struct expression *right;
363 368 sval_t sval;
364 369
365 370 right = strip_expr(expr->right);
366 371
367 372 if (right->type != EXPR_BINOP || right->op != '-')
368 373 return 0;
369 374
370 375 if (!get_value(right->right, &sval))
371 376 return 0;
372 377
373 378 right = get_assigned_expr(right->left);
374 379 if (!right)
375 380 return 0;
376 381 return copy_containter_states(expr->left, right, sval.value);
377 382 }
378 383
379 384 static void returns_container_of(struct expression *expr, int param, char *key, char *value)
380 385 {
381 386 struct expression *call, *arg;
382 387 int offset;
383 388
384 389 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
385 390 return;
386 391 call = strip_expr(expr->right);
387 392 if (call->type != EXPR_CALL)
388 393 return;
389 394 if (param != -1)
390 395 return;
391 396 param = atoi(key);
392 397 offset = atoi(value);
393 398
394 399 arg = get_argument_from_call_expr(call->args, param);
395 400 if (!arg)
396 401 return;
397 402
398 403 copy_containter_states(expr->left, arg, -offset);
399 404 }
400 405
401 406 void __fake_struct_member_assignments(struct expression *expr)
402 407 {
403 408 struct symbol *left_type;
404 409
405 410 if (expr->op != '=')
406 411 return;
407 412
408 413 if (expr_is_zero(expr->right))
409 414 return;
410 415
411 416 left_type = get_type(expr->left);
412 417 if (!left_type ||
413 418 (left_type->type != SYM_PTR &&
414 419 left_type->type != SYM_STRUCT))
415 420 return;
416 421
417 422 if (handle_param_offsets(expr))
418 423 return;
419 424
420 425 if (returns_zeroed_mem(expr->right))
421 426 __struct_members_copy(COPY_MEMSET, expr, expr->left, zero_expr());
422 427 else
423 428 __struct_members_copy(COPY_NORMAL, expr, expr->left, expr->right);
424 429 }
425 430
426 431 static void match_memset(const char *fn, struct expression *expr, void *_size_arg)
427 432 {
428 433 struct expression *buf;
429 434 struct expression *val;
430 435
431 436 buf = get_argument_from_call_expr(expr->args, 0);
432 437 val = get_argument_from_call_expr(expr->args, 1);
433 438
434 439 buf = strip_expr(buf);
435 440 __struct_members_copy(COPY_MEMSET, expr, remove_addr(buf), val);
436 441 }
437 442
438 443 static void match_memcpy(const char *fn, struct expression *expr, void *_arg)
439 444 {
440 445 struct expression *dest;
441 446 struct expression *src;
442 447
443 448 dest = get_argument_from_call_expr(expr->args, 0);
444 449 src = get_argument_from_call_expr(expr->args, 1);
445 450
446 451 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), remove_addr(src));
447 452 }
448 453
449 454 static void match_memdup(const char *fn, struct expression *call_expr,
450 455 struct expression *expr, void *_unused)
451 456 {
452 457 struct expression *left, *right, *arg;
453 458
454 459 if (!expr || expr->type != EXPR_ASSIGNMENT)
455 460 return;
456 461
457 462 left = strip_expr(expr->left);
458 463 right = strip_expr(expr->right);
459 464
460 465 if (right->type != EXPR_CALL)
461 466 return;
462 467 arg = get_argument_from_call_expr(right->args, 0);
463 468 __struct_members_copy(COPY_MEMCPY, expr, left, arg);
464 469 }
465 470
466 471 static void match_memcpy_unknown(const char *fn, struct expression *expr, void *_arg)
467 472 {
468 473 struct expression *dest;
469 474
470 475 dest = get_argument_from_call_expr(expr->args, 0);
471 476 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), NULL);
472 477 }
473 478
474 479 static void match_sscanf(const char *fn, struct expression *expr, void *unused)
475 480 {
476 481 struct expression *arg;
477 482 int i;
478 483
479 484 i = -1;
480 485 FOR_EACH_PTR(expr->args, arg) {
481 486 if (++i < 2)
482 487 continue;
483 488 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(arg), NULL);
484 489 } END_FOR_EACH_PTR(arg);
485 490 }
486 491
487 492 static void unop_expr(struct expression *expr)
488 493 {
489 494 if (expr->op != SPECIAL_INCREMENT &&
490 495 expr->op != SPECIAL_DECREMENT)
491 496 return;
492 497
493 498 if (!is_pointer(expr))
494 499 return;
495 500 faked_expression = expr;
496 501 __struct_members_copy(COPY_MEMCPY, expr, expr->unop, NULL);
497 502 faked_expression = NULL;
498 503 }
499 504
500 505 static void register_clears_param(void)
501 506 {
502 507 struct token *token;
503 508 char name[256];
504 509 const char *function;
505 510 int param;
506 511
507 512 if (option_project == PROJ_NONE)
508 513 return;
509 514
510 515 snprintf(name, 256, "%s.clears_argument", option_project_str);
511 516
512 517 token = get_tokens_file(name);
513 518 if (!token)
514 519 return;
515 520 if (token_type(token) != TOKEN_STREAMBEGIN)
516 521 return;
517 522 token = token->next;
518 523 while (token_type(token) != TOKEN_STREAMEND) {
519 524 if (token_type(token) != TOKEN_IDENT)
520 525 return;
521 526 function = show_ident(token->ident);
522 527 token = token->next;
523 528 if (token_type(token) != TOKEN_NUMBER)
524 529 return;
525 530 param = atoi(token->number);
526 531 add_function_hook(function, &match_memcpy_unknown, INT_PTR(param));
527 532 token = token->next;
528 533 }
529 534 clear_token_alloc();
530 535 }
531 536
532 537 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
533 538 {
534 539 struct expression *arg;
535 540
536 541 while (expr->type == EXPR_ASSIGNMENT)
537 542 expr = strip_expr(expr->right);
538 543 if (expr->type != EXPR_CALL)
539 544 return;
540 545
541 546 /*
542 547 * FIXME: __struct_members_copy() requires an expression but
543 548 * get_variable_from_key() returns a name/sym pair so that doesn't
544 549 * work here.
545 550 */
546 551 if (strcmp(key, "$") != 0)
547 552 return;
548 553
549 554 arg = get_argument_from_call_expr(expr->args, param);
550 555 if (!arg)
551 556 return;
552 557
553 558 if (strcmp(value, "0") == 0)
554 559 __struct_members_copy(COPY_MEMSET, expr, remove_addr(arg), zero_expr());
555 560 else
556 561 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(arg), NULL);
557 562 }
558 563
559 564 void register_struct_assignment(int id)
560 565 {
561 566 add_function_hook("memset", &match_memset, NULL);
562 567 add_function_hook("__memset", &match_memset, NULL);
563 568
564 569 add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
565 570 add_function_hook("memmove", &match_memcpy, INT_PTR(0));
566 571 add_function_hook("__memcpy", &match_memcpy, INT_PTR(0));
567 572 add_function_hook("__memmove", &match_memcpy, INT_PTR(0));
568 573
569 574 if (option_project == PROJ_KERNEL)
570 575 return_implies_state_sval("kmemdup", valid_ptr_min_sval, valid_ptr_max_sval, &match_memdup, NULL);
571 576
572 577 add_function_hook("sscanf", &match_sscanf, NULL);
573 578
574 579 add_hook(&unop_expr, OP_HOOK);
575 580 register_clears_param();
576 581 select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
577 582
578 583 select_return_states_hook(CONTAINER, &returns_container_of);
579 584 }
↓ open down ↓ |
325 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX