Print this page
11506 smatch resync
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++;
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 154 type = get_type(left);
155 155 if (!type)
156 156 return;
157 157 if (type->type == SYM_PTR) {
158 158 left = deref_expression(left);
159 159 if (right)
160 160 right = deref_expression(right);
161 161 else
162 162 right = unknown_value_expression(left);
163 163 assign = assign_expression(left, '=', right);
164 164 split_fake_expr(assign);
165 165 return;
166 166 }
167 167 if (type->type != SYM_BASETYPE)
168 168 return;
169 169 right = strip_expr(right);
170 170 if (!right)
171 171 right = unknown_value_expression(left);
172 172 assign = assign_expression(left, '=', right);
173 173 split_fake_expr(assign);
174 174 }
175 175
176 176 static void set_inner_struct_members(int mode, struct expression *faked, struct expression *left, struct expression *right, struct symbol *member)
177 177 {
178 178 struct expression *left_member;
179 179 struct expression *right_member = NULL; /* silence GCC */
180 180 struct expression *assign;
181 181 struct symbol *base = get_real_base_type(member);
182 182 struct symbol *tmp;
183 183
184 184 if (member->ident) {
185 185 left = member_expression(left, '.', member->ident);
186 186 if (mode != COPY_MEMSET && right)
187 187 right = member_expression(right, '.', member->ident);
188 188 }
189 189
190 190 FOR_EACH_PTR(base->symbol_list, tmp) {
191 191 struct symbol *type;
192 192
193 193 type = get_real_base_type(tmp);
194 194 if (!type)
195 195 continue;
196 196
197 197 if (type->type == SYM_ARRAY)
198 198 continue;
199 199 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
200 200 set_inner_struct_members(mode, faked, left, right, tmp);
201 201 continue;
202 202 }
203 203 if (!tmp->ident)
204 204 continue;
205 205
206 206 left_member = member_expression(left, '.', tmp->ident);
207 207
208 208 switch (mode) {
209 209 case COPY_NORMAL:
210 210 case COPY_MEMCPY:
211 211 if (right)
212 212 right_member = member_expression(right, '.', tmp->ident);
213 213 else
214 214 right_member = unknown_value_expression(left_member);
215 215 break;
216 216 case COPY_MEMSET:
217 217 right_member = right;
218 218 break;
219 219 }
220 220
221 221 assign = assign_expression(left_member, '=', right_member);
222 222 split_fake_expr(assign);
223 223 } END_FOR_EACH_PTR(tmp);
224 224 }
225 225
226 226 static void __struct_members_copy(int mode, struct expression *faked,
227 227 struct expression *left,
228 228 struct expression *right)
229 229 {
230 230 struct symbol *struct_type, *tmp, *type;
231 231 struct expression *left_member;
232 232 struct expression *right_member;
233 233 struct expression *assign;
234 234 int op = '.';
235 235
236 236
237 237 if (__in_fake_assign)
238 238 return;
239 239 faked_expression = faked;
240 240
241 241 left = strip_expr(left);
242 242 right = strip_expr(right);
243 243
244 244 struct_type = get_struct_type(left);
245 245 if (!struct_type) {
246 246 /*
247 247 * This is not a struct assignment obviously. But this is where
248 248 * memcpy() is handled so it feels like a good place to add this
249 249 * code.
250 250 */
251 251 handle_non_struct_assignments(left, right);
252 252 goto done;
253 253 }
254 254
255 255 if (is_pointer(left)) {
256 256 left = deref_expression(left);
257 257 op = '*';
258 258 }
259 259 if (mode != COPY_MEMSET)
260 260 right = get_right_base_expr(struct_type, right);
261 261
262 262 FOR_EACH_PTR(struct_type->symbol_list, tmp) {
263 263 type = get_real_base_type(tmp);
264 264 if (!type)
265 265 continue;
266 266 if (type->type == SYM_ARRAY)
267 267 continue;
268 268
269 269 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
270 270 set_inner_struct_members(mode, faked, left, right, tmp);
271 271 continue;
272 272 }
273 273
274 274 if (!tmp->ident)
275 275 continue;
276 276
277 277 left_member = member_expression(left, op, tmp->ident);
278 278 right_member = NULL;
279 279
280 280 switch (mode) {
281 281 case COPY_NORMAL:
282 282 case COPY_MEMCPY:
283 283 if (right)
284 284 right_member = member_expression(right, op, tmp->ident);
285 285 else
286 286 right_member = unknown_value_expression(left_member);
287 287 break;
288 288 case COPY_MEMSET:
289 289 right_member = right;
290 290 break;
291 291 }
292 292 if (!right_member) {
293 293 sm_perror("No right member");
294 294 continue;
295 295 }
296 296 assign = assign_expression(left_member, '=', right_member);
297 297 split_fake_expr(assign);
298 298 } END_FOR_EACH_PTR(tmp);
299 299
300 300 done:
301 301 faked_expression = NULL;
302 302 }
303 303
304 304 static int returns_zeroed_mem(struct expression *expr)
305 305 {
306 306 char *fn;
307 307
308 308 if (expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL)
309 309 return 0;
310 310 fn = expr_to_var(expr->fn);
311 311 if (!fn)
312 312 return 0;
313 313 if (strcmp(fn, "kcalloc") == 0)
314 314 return 1;
315 315 if (option_project == PROJ_KERNEL && strstr(fn, "zalloc"))
316 316 return 1;
317 317 return 0;
318 318 }
319 319
320 320 static int copy_containter_states(struct expression *left, struct expression *right, int offset)
321 321 {
322 322 char *left_name = NULL, *right_name = NULL;
323 323 struct symbol *left_sym, *right_sym;
324 324 struct sm_state *sm, *new_sm;
325 325 int ret = 0;
326 326 int len;
327 327 char buf[64];
328 328 char new_name[128];
329 329
330 330 right_name = expr_to_var_sym(right, &right_sym);
331 331 if (!right_name || !right_sym)
332 332 goto free;
333 333 left_name = expr_to_var_sym(left, &left_sym);
334 334 if (!left_name || !left_sym)
335 335 goto free;
336 336
337 337 len = snprintf(buf, sizeof(buf), "%s(-%d)", right_name, offset);
338 338 if (len >= sizeof(buf))
339 339 goto free;
340 340
341 341 FOR_EACH_SM(__get_cur_stree(), sm) {
342 342 if (sm->sym != right_sym)
343 343 continue;
344 344 if (strncmp(sm->name, buf, len) != 0)
345 345 continue;
346 346 snprintf(new_name, sizeof(new_name), "%s%s", left_name, sm->name + len);
347 347 new_sm = clone_sm(sm);
348 348 new_sm->name = alloc_sname(new_name);
349 349 new_sm->sym = left_sym;
350 350 __set_sm(new_sm);
351 351 ret = 1;
352 352 } END_FOR_EACH_SM(sm);
353 353 free:
354 354 free_string(left_name);
355 355 free_string(right_name);
356 356 return ret;
357 357 }
358 358
359 359 static int handle_param_offsets(struct expression *expr)
360 360 {
361 361 struct expression *right;
362 362 sval_t sval;
363 363
364 364 right = strip_expr(expr->right);
365 365
366 366 if (right->type != EXPR_BINOP || right->op != '-')
367 367 return 0;
368 368
369 369 if (!get_value(right->right, &sval))
370 370 return 0;
371 371
372 372 right = get_assigned_expr(right->left);
373 373 if (!right)
374 374 return 0;
375 375 return copy_containter_states(expr->left, right, sval.value);
376 376 }
377 377
378 378 static void returns_container_of(struct expression *expr, int param, char *key, char *value)
379 379 {
380 380 struct expression *call, *arg;
381 381 int offset;
382 382
383 383 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
384 384 return;
385 385 call = strip_expr(expr->right);
386 386 if (call->type != EXPR_CALL)
387 387 return;
388 388 if (param != -1)
389 389 return;
390 390 param = atoi(key);
391 391 offset = atoi(value);
392 392
393 393 arg = get_argument_from_call_expr(call->args, param);
394 394 if (!arg)
395 395 return;
396 396
397 397 copy_containter_states(expr->left, arg, -offset);
398 398 }
399 399
400 400 void __fake_struct_member_assignments(struct expression *expr)
401 401 {
402 402 struct symbol *left_type;
403 403
404 404 if (expr->op != '=')
405 405 return;
406 406
407 407 if (is_zero(expr->right))
408 408 return;
409 409
410 410 left_type = get_type(expr->left);
411 411 if (!left_type ||
412 412 (left_type->type != SYM_PTR &&
413 413 left_type->type != SYM_STRUCT))
414 414 return;
415 415
416 416 if (handle_param_offsets(expr))
417 417 return;
418 418
419 419 if (returns_zeroed_mem(expr->right))
420 420 __struct_members_copy(COPY_MEMSET, expr, expr->left, zero_expr());
421 421 else
422 422 __struct_members_copy(COPY_NORMAL, expr, expr->left, expr->right);
423 423 }
424 424
425 425 static void match_memset(const char *fn, struct expression *expr, void *_size_arg)
426 426 {
427 427 struct expression *buf;
428 428 struct expression *val;
429 429
430 430 buf = get_argument_from_call_expr(expr->args, 0);
431 431 val = get_argument_from_call_expr(expr->args, 1);
432 432
433 433 buf = strip_expr(buf);
434 434 __struct_members_copy(COPY_MEMSET, expr, remove_addr(buf), val);
435 435 }
436 436
437 437 static void match_memcpy(const char *fn, struct expression *expr, void *_arg)
↓ open down ↓ |
437 lines elided |
↑ open up ↑ |
438 438 {
439 439 struct expression *dest;
440 440 struct expression *src;
441 441
442 442 dest = get_argument_from_call_expr(expr->args, 0);
443 443 src = get_argument_from_call_expr(expr->args, 1);
444 444
445 445 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), remove_addr(src));
446 446 }
447 447
448 +static void match_memdup(const char *fn, struct expression *call_expr,
449 + struct expression *expr, void *_unused)
450 +{
451 + struct expression *left, *right, *arg;
452 +
453 + if (!expr || expr->type != EXPR_ASSIGNMENT)
454 + return;
455 +
456 + left = strip_expr(expr->left);
457 + right = strip_expr(expr->right);
458 +
459 + if (right->type != EXPR_CALL)
460 + return;
461 + arg = get_argument_from_call_expr(right->args, 0);
462 + __struct_members_copy(COPY_MEMCPY, expr, left, arg);
463 +}
464 +
448 465 static void match_memcpy_unknown(const char *fn, struct expression *expr, void *_arg)
449 466 {
450 467 struct expression *dest;
451 468
452 469 dest = get_argument_from_call_expr(expr->args, 0);
453 470 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), NULL);
454 471 }
455 472
456 473 static void match_sscanf(const char *fn, struct expression *expr, void *unused)
457 474 {
458 475 struct expression *arg;
459 476 int i;
460 477
461 478 i = -1;
462 479 FOR_EACH_PTR(expr->args, arg) {
463 480 if (++i < 2)
464 481 continue;
465 482 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(arg), NULL);
466 483 } END_FOR_EACH_PTR(arg);
467 484 }
468 485
469 486 static void unop_expr(struct expression *expr)
470 487 {
471 488 if (expr->op != SPECIAL_INCREMENT &&
472 489 expr->op != SPECIAL_DECREMENT)
473 490 return;
474 491
475 492 if (!is_pointer(expr))
476 493 return;
477 494 faked_expression = expr;
478 495 __struct_members_copy(COPY_MEMCPY, expr, expr->unop, NULL);
479 496 faked_expression = NULL;
480 497 }
481 498
482 499 static void register_clears_param(void)
483 500 {
484 501 struct token *token;
485 502 char name[256];
486 503 const char *function;
487 504 int param;
488 505
489 506 if (option_project == PROJ_NONE)
490 507 return;
491 508
492 509 snprintf(name, 256, "%s.clears_argument", option_project_str);
493 510
494 511 token = get_tokens_file(name);
495 512 if (!token)
496 513 return;
497 514 if (token_type(token) != TOKEN_STREAMBEGIN)
498 515 return;
499 516 token = token->next;
500 517 while (token_type(token) != TOKEN_STREAMEND) {
501 518 if (token_type(token) != TOKEN_IDENT)
502 519 return;
503 520 function = show_ident(token->ident);
504 521 token = token->next;
505 522 if (token_type(token) != TOKEN_NUMBER)
506 523 return;
507 524 param = atoi(token->number);
508 525 add_function_hook(function, &match_memcpy_unknown, INT_PTR(param));
509 526 token = token->next;
510 527 }
511 528 clear_token_alloc();
512 529 }
513 530
514 531 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
515 532 {
516 533 struct expression *arg;
517 534
518 535 while (expr->type == EXPR_ASSIGNMENT)
519 536 expr = strip_expr(expr->right);
520 537 if (expr->type != EXPR_CALL)
521 538 return;
522 539
523 540 /*
524 541 * FIXME: __struct_members_copy() requires an expression but
525 542 * get_variable_from_key() returns a name/sym pair so that doesn't
526 543 * work here.
527 544 */
528 545 if (strcmp(key, "$") != 0)
529 546 return;
530 547
531 548 arg = get_argument_from_call_expr(expr->args, param);
532 549 if (!arg)
533 550 return;
534 551
535 552 if (strcmp(value, "0") == 0)
536 553 __struct_members_copy(COPY_MEMSET, expr, remove_addr(arg), zero_expr());
537 554 else
538 555 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(arg), NULL);
539 556 }
540 557
↓ open down ↓ |
83 lines elided |
↑ open up ↑ |
541 558 void register_struct_assignment(int id)
542 559 {
543 560 add_function_hook("memset", &match_memset, NULL);
544 561 add_function_hook("__memset", &match_memset, NULL);
545 562
546 563 add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
547 564 add_function_hook("memmove", &match_memcpy, INT_PTR(0));
548 565 add_function_hook("__memcpy", &match_memcpy, INT_PTR(0));
549 566 add_function_hook("__memmove", &match_memcpy, INT_PTR(0));
550 567
568 + if (option_project == PROJ_KERNEL)
569 + return_implies_state_sval("kmemdup", valid_ptr_min_sval, valid_ptr_max_sval, &match_memdup, NULL);
570 +
551 571 add_function_hook("sscanf", &match_sscanf, NULL);
552 572
553 573 add_hook(&unop_expr, OP_HOOK);
554 574 register_clears_param();
555 575 select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
556 576
557 577 select_return_states_hook(CONTAINER, &returns_container_of);
558 578 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX