kernel.no_return_funcs: add kunit_do_failed_assertion()
[smatch/bkmgit.git] / smatch_struct_assignment.c
blob2d0a99d7ef2cab84105183e50ca2634b8027e109
1 /*
2 * Copyright (C) 2014 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * This file started out by saying that if you have:
21 * struct foo one, two;
22 * ...
23 * one = two;
25 * That's equivalent to saying:
27 * one.x = two.x;
28 * one.y = two.y;
30 * Turning an assignment like that into a bunch of small fake assignments is
31 * really useful.
33 * The call to memcpy(&one, &two, sizeof(foo)); is the same as "one = two;" so
34 * we can re-use the code. And we may as well use it for memset() too.
35 * Assigning pointers is almost the same:
37 * p1 = p2;
39 * Is the same as:
41 * p1->x = p2->x;
42 * p1->y = p2->y;
44 * The problem is that you can go a bit crazy with pointers to pointers.
46 * p1->x->y->z->one->two->three = p2->x->y->z->one->two->three;
48 * We probably want to distinguish between between shallow and deep copies so
49 * that if we memset(p1, 0, sizeof(*p1)) then it just sets p1->x to zero and not
50 * p1->x->y.
52 * I don't have a proper solution for this problem right now. I just copy one
53 * level and don't nest. It should handle limitted nesting but intelligently.
55 * The other thing is that you end up with a lot of garbage assignments where
56 * we record "x could be anything. x->y could be anything. x->y->z->a->b->c
57 * could *also* be anything!". There should be a better way to filter this
58 * useless information.
62 #include "smatch.h"
63 #include "smatch_slist.h"
64 #include "smatch_extra.h"
66 enum {
67 COPY_NORMAL,
68 COPY_UNKNOWN,
69 COPY_ZERO,
72 static struct symbol *get_struct_type(struct expression *expr)
74 struct symbol *type;
76 type = get_type(expr);
77 if (!type)
78 return NULL;
79 if (type->type == SYM_PTR) {
80 type = get_real_base_type(type);
81 if (!type)
82 return NULL;
84 if (type->type == SYM_STRUCT)
85 return type;
86 if (type->type == SYM_UNION)
87 return type;
88 return NULL;
91 static struct expression *get_right_base_expr(struct symbol *left_type, struct expression *right)
93 struct symbol *struct_type;
95 if (!right)
96 return NULL;
98 struct_type = get_struct_type(right);
99 if (!struct_type)
100 return NULL;
101 if (struct_type != left_type)
102 return NULL;
104 if (right->type == EXPR_PREOP && right->op == '&')
105 right = strip_expr(right->unop);
107 if (right->type == EXPR_CALL)
108 return NULL;
110 return right;
113 static struct expression *add_dereference(struct expression *expr)
115 struct symbol *type;
118 * We want to re-write "memcpy(foo, bar, sizeof(*foo));" as
119 * "*foo = *bar;".
122 expr = strip_expr(expr);
123 if (!expr)
124 return NULL;
126 if (expr->type == EXPR_PREOP && expr->op == '&')
127 return strip_expr(expr->unop);
128 type = get_type(expr);
129 if (!type)
130 return NULL;
131 if (type->type != SYM_PTR && type->type != SYM_ARRAY)
132 return NULL;
134 return deref_expression(expr);
137 static struct expression *faked_expression;
138 struct expression *get_faked_expression(void)
140 if (!__in_fake_assign)
141 return NULL;
142 return faked_expression;
145 static void split_fake_expr(struct expression *expr, void *unused)
147 __in_fake_assign++;
148 __in_fake_struct_assign++;
149 __split_expr(expr);
150 __in_fake_struct_assign--;
151 __in_fake_assign--;
154 static void handle_non_struct_assignments(struct expression *left, struct expression *right,
155 void (*assign_handler)(struct expression *expr, void *data),
156 void *data)
158 struct symbol *left_type, *right_type;
159 struct expression *assign;
161 while (right && right->type == EXPR_ASSIGNMENT)
162 right = strip_parens(right->left);
164 if (!right)
165 right = unknown_value_expression(left);
167 left_type = get_type(left);
168 right_type = get_type(right);
169 if (!left_type || !right_type)
170 return;
172 if (right_type->type == SYM_ARRAY)
173 right = unknown_value_expression(left);
175 if (left_type->type == SYM_PTR) {
176 left = deref_expression(left);
177 assign = assign_expression(left, '=', right);
178 assign_handler(assign, data);
179 return;
181 if (left_type->type != SYM_BASETYPE)
182 return;
183 assign = assign_expression(left, '=', right);
184 assign_handler(assign, data);
187 static void set_inner_struct_members(int mode, struct expression *faked,
188 struct expression *left, struct expression *right, struct symbol *member,
189 void (*assign_handler)(struct expression *expr, void *data),
190 void *data)
192 struct expression *left_member;
193 struct expression *right_expr = NULL; /* silence GCC */
194 struct expression *assign;
195 struct symbol *base = get_real_base_type(member);
196 struct symbol *tmp;
198 if (member->ident) {
199 left = member_expression(left, '.', member->ident);
200 if (mode == COPY_NORMAL && right)
201 right = member_expression(right, '.', member->ident);
204 FOR_EACH_PTR(base->symbol_list, tmp) {
205 struct symbol *type;
207 type = get_real_base_type(tmp);
208 if (!type)
209 continue;
211 if (type->type == SYM_ARRAY)
212 continue;
213 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
214 set_inner_struct_members(mode, faked, left, right, tmp, assign_handler, data);
215 continue;
217 if (!tmp->ident)
218 continue;
220 left_member = member_expression(left, '.', tmp->ident);
222 right_expr = NULL;
223 if (mode == COPY_NORMAL && right)
224 right_expr = member_expression(right, '.', tmp->ident);
225 if (mode == COPY_ZERO)
226 right_expr = zero_expr();
227 if (!right_expr)
228 right_expr = unknown_value_expression(left_member);
230 assign = assign_expression(left_member, '=', right_expr);
231 assign_handler(assign, data);
232 } END_FOR_EACH_PTR(tmp);
235 static void __struct_members_copy(int mode, struct expression *faked,
236 struct expression *left,
237 struct expression *right,
238 void (*assign_handler)(struct expression *expr, void *data),
239 void *data)
241 struct symbol *struct_type, *tmp, *type;
242 struct expression *left_member;
243 struct expression *right_expr;
244 struct expression *assign;
246 if (__in_fake_assign || !left)
247 return;
248 faked_expression = faked;
250 left = strip_expr(left);
251 right = strip_expr(right);
253 if (left->type == EXPR_PREOP && left->op == '*' && is_pointer(left))
254 left = preop_expression(left, '(');
256 struct_type = get_struct_type(left);
257 if (!struct_type) {
259 * This is not a struct assignment obviously. But this is where
260 * memcpy() is handled so it feels like a good place to add this
261 * code.
263 handle_non_struct_assignments(left, right, assign_handler, data);
264 goto done;
267 if (mode == COPY_NORMAL)
268 right = get_right_base_expr(struct_type, right);
270 FOR_EACH_PTR(struct_type->symbol_list, tmp) {
271 type = get_real_base_type(tmp);
272 if (!type)
273 continue;
274 if (type->type == SYM_ARRAY)
275 continue;
277 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
278 set_inner_struct_members(mode, faked, left, right, tmp, assign_handler, data);
279 continue;
282 if (!tmp->ident)
283 continue;
285 left_member = member_expression(left, '.', tmp->ident);
286 right_expr = NULL;
288 if (mode == COPY_NORMAL && right)
289 right_expr = member_expression(right, '.', tmp->ident);
290 if (mode == COPY_ZERO)
291 right_expr = zero_expr();
292 if (!right_expr)
293 right_expr = unknown_value_expression(left_member);
295 assign = assign_expression(left_member, '=', right_expr);
296 assign_handler(assign, data);
297 } END_FOR_EACH_PTR(tmp);
299 done:
300 faked_expression = NULL;
303 static int returns_zeroed_mem(struct expression *expr)
305 struct expression *tmp;
306 char *fn;
308 if (expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL)
309 return 0;
311 if (is_fake_call(expr)) {
312 tmp = get_faked_expression();
313 if (!tmp || tmp->type != EXPR_ASSIGNMENT || tmp->op != '=')
314 return 0;
315 expr = tmp->right;
316 if (expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL)
317 return 0;
320 fn = expr_to_var(expr->fn);
321 if (!fn)
322 return 0;
323 if (strcmp(fn, "kcalloc") == 0)
324 return 1;
325 if (option_project == PROJ_KERNEL && strstr(fn, "zalloc"))
326 return 1;
327 return 0;
330 static int copy_containter_states(struct expression *left, struct expression *right, int offset)
332 char *left_name = NULL, *right_name = NULL;
333 struct symbol *left_sym, *right_sym;
334 struct sm_state *sm, *new_sm;
335 int ret = 0;
336 int len;
337 char buf[64];
338 char new_name[128];
340 right_name = expr_to_var_sym(right, &right_sym);
341 if (!right_name || !right_sym)
342 goto free;
343 left_name = expr_to_var_sym(left, &left_sym);
344 if (!left_name || !left_sym)
345 goto free;
347 len = snprintf(buf, sizeof(buf), "%s(-%d)", right_name, offset);
348 if (len >= sizeof(buf))
349 goto free;
351 FOR_EACH_SM_SAFE(__get_cur_stree(), sm) {
352 if (sm->sym != right_sym)
353 continue;
354 if (strncmp(sm->name, buf, len) != 0)
355 continue;
356 snprintf(new_name, sizeof(new_name), "%s%s", left_name, sm->name + len);
357 new_sm = clone_sm(sm);
358 new_sm->name = alloc_sname(new_name);
359 new_sm->sym = left_sym;
360 __set_sm(new_sm);
361 ret = 1;
362 } END_FOR_EACH_SM_SAFE(sm);
363 free:
364 free_string(left_name);
365 free_string(right_name);
366 return ret;
369 static int handle_param_offsets(struct expression *expr)
371 struct expression *right;
372 sval_t sval;
374 right = strip_expr(expr->right);
376 if (right->type != EXPR_BINOP || right->op != '-')
377 return 0;
379 if (!get_value(right->right, &sval))
380 return 0;
382 right = get_assigned_expr(right->left);
383 if (!right)
384 return 0;
385 return copy_containter_states(expr->left, right, sval.value);
388 static void returns_container_of(struct expression *expr, int param, char *key, char *value)
390 struct expression *call, *arg;
391 int offset;
393 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
394 return;
395 call = strip_expr(expr->right);
396 if (call->type != EXPR_CALL)
397 return;
398 if (param != -1)
399 return;
400 param = atoi(key);
401 offset = atoi(value);
403 arg = get_argument_from_call_expr(call->args, param);
404 if (!arg)
405 return;
407 copy_containter_states(expr->left, arg, -offset);
410 void __fake_struct_member_assignments(struct expression *expr)
412 struct expression *left, *right;
413 struct symbol *type;
414 int mode;
416 if (expr->op != '=')
417 return;
419 if (is_noderef_ptr(expr->right))
420 return;
422 type = get_type(expr->left);
423 if (!type)
424 return;
425 if (type->type != SYM_PTR && type->type != SYM_STRUCT)
426 return;
428 if (handle_param_offsets(expr))
429 return;
431 left = expr->left;
432 right = expr->right;
434 if (type->type == SYM_PTR) {
435 /* Convert "p = q;" to "*p = *q;" */
436 left = add_dereference(left);
437 right = add_dereference(right);
440 if (returns_zeroed_mem(expr->right))
441 mode = COPY_ZERO;
442 else if (types_equiv(get_type(left), get_type(right)))
443 mode = COPY_NORMAL;
444 else
445 mode = COPY_UNKNOWN;
447 __struct_members_copy(mode, expr, left, right, split_fake_expr, NULL);
450 static void match_memset(const char *fn, struct expression *expr, void *_size_arg)
452 struct expression *buf;
453 struct expression *val;
454 int mode;
456 buf = get_argument_from_call_expr(expr->args, 0);
457 val = get_argument_from_call_expr(expr->args, 1);
459 buf = strip_expr(buf);
460 if (expr_is_zero(val))
461 mode = COPY_ZERO;
462 else
463 mode = COPY_UNKNOWN;
464 __struct_members_copy(mode, expr, add_dereference(buf), NULL, split_fake_expr, NULL);
467 static void match_memcpy(const char *fn, struct expression *expr, void *_arg)
469 struct expression *dest;
470 struct expression *src;
471 int mode;
473 dest = get_argument_from_call_expr(expr->args, 0);
474 src = get_argument_from_call_expr(expr->args, 1);
476 if (types_equiv(get_type(src), get_type(dest)))
477 mode = COPY_NORMAL;
478 else
479 mode = COPY_UNKNOWN;
481 __struct_members_copy(mode, expr, add_dereference(dest), add_dereference(src), split_fake_expr, NULL);
484 static void match_memdup(const char *fn, struct expression *call_expr,
485 struct expression *expr, void *_unused)
487 struct expression *left, *right, *arg;
488 int mode;
490 if (!expr || expr->type != EXPR_ASSIGNMENT)
491 return;
493 left = strip_expr(expr->left);
494 right = strip_expr(expr->right);
496 if (right->type != EXPR_CALL)
497 return;
498 arg = get_argument_from_call_expr(right->args, 0);
500 if (types_equiv(get_type(left), get_type(right)))
501 mode = COPY_NORMAL;
502 else
503 mode = COPY_UNKNOWN;
505 __struct_members_copy(mode, expr, add_dereference(left), add_dereference(arg), split_fake_expr, NULL);
508 static void match_memcpy_unknown(const char *fn, struct expression *expr, void *_arg)
510 struct expression *dest;
512 dest = get_argument_from_call_expr(expr->args, 0);
513 __struct_members_copy(COPY_UNKNOWN, expr, add_dereference(dest), NULL, split_fake_expr, NULL);
516 static void match_sscanf(const char *fn, struct expression *expr, void *unused)
518 struct expression *arg;
519 int i;
521 i = -1;
522 FOR_EACH_PTR(expr->args, arg) {
523 if (++i < 2)
524 continue;
525 __struct_members_copy(COPY_UNKNOWN, expr, add_dereference(arg), NULL, split_fake_expr, NULL);
526 } END_FOR_EACH_PTR(arg);
529 static void unop_expr(struct expression *expr)
531 if (expr->op != SPECIAL_INCREMENT &&
532 expr->op != SPECIAL_DECREMENT)
533 return;
535 if (!is_pointer(expr))
536 return;
537 faked_expression = expr;
538 __struct_members_copy(COPY_UNKNOWN, expr, expr->unop, NULL, split_fake_expr, NULL);
539 faked_expression = NULL;
542 static void register_clears_param(void)
544 struct token *token;
545 char name[256];
546 const char *function;
547 int param;
549 if (option_project == PROJ_NONE)
550 return;
552 snprintf(name, 256, "%s.clears_argument", option_project_str);
554 token = get_tokens_file(name);
555 if (!token)
556 return;
557 if (token_type(token) != TOKEN_STREAMBEGIN)
558 return;
559 token = token->next;
560 while (token_type(token) != TOKEN_STREAMEND) {
561 if (token_type(token) != TOKEN_IDENT)
562 return;
563 function = show_ident(token->ident);
564 token = token->next;
565 if (token_type(token) != TOKEN_NUMBER)
566 return;
567 param = atoi(token->number);
568 add_function_hook(function, &match_memcpy_unknown, INT_PTR(param));
569 token = token->next;
571 clear_token_alloc();
574 void create_recursive_fake_assignments(struct expression *expr,
575 void (*assign_handler)(struct expression *expr, void *data),
576 void *data)
578 __struct_members_copy(COPY_UNKNOWN, expr, expr, NULL, assign_handler, data);
581 static void db_buf_cleared(struct expression *expr, int param, char *key, char *value)
583 struct expression *arg;
585 arg = gen_expr_from_param_key(expr, param, key);
586 if (!arg)
587 return;
589 __in_buf_clear++;
590 if (strcmp(value, "0") == 0)
591 __struct_members_copy(COPY_ZERO, expr, arg, NULL, split_fake_expr, NULL);
592 else
593 __struct_members_copy(COPY_UNKNOWN, expr, arg, NULL, split_fake_expr, NULL);
594 __in_buf_clear--;
597 static void db_param_add_set(struct expression *expr, int param, char *key, char *value)
599 struct expression *arg;
600 struct symbol *type;
602 arg = gen_expr_from_param_key(expr, param, key);
603 if (!arg)
604 return;
605 type = get_type(arg);
606 if (!type)
607 return;
608 if (type->type != SYM_STRUCT && type->type != SYM_UNION)
609 return;
611 __struct_members_copy(COPY_UNKNOWN, expr, arg, NULL, split_fake_expr, NULL);
614 void register_struct_assignment(int id)
616 add_function_data((unsigned long *)&faked_expression);
618 add_function_hook("memset", &match_memset, NULL);
619 add_function_hook("__memset", &match_memset, NULL);
620 add_function_hook("__builtin_memset", &match_memset, NULL);
622 add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
623 add_function_hook("memmove", &match_memcpy, INT_PTR(0));
624 add_function_hook("__memcpy", &match_memcpy, INT_PTR(0));
625 add_function_hook("__memmove", &match_memcpy, INT_PTR(0));
626 add_function_hook("__builtin_memcpy", &match_memcpy, INT_PTR(0));
627 add_function_hook("__builtin_memmove", &match_memcpy, INT_PTR(0));
629 if (option_project == PROJ_KERNEL) {
630 return_implies_state_sval("kmemdup", valid_ptr_min_sval, valid_ptr_max_sval, &match_memdup, NULL);
631 add_function_hook("copy_from_user", &match_memcpy, INT_PTR(0));
632 add_function_hook("_copy_from_user", &match_memcpy, INT_PTR(0));
635 add_function_hook("sscanf", &match_sscanf, NULL);
637 add_hook(&unop_expr, OP_HOOK);
638 register_clears_param();
639 select_return_states_hook(BUF_CLEARED, &db_buf_cleared);
640 select_return_states_hook(PARAM_ADD, &db_param_add_set);
641 select_return_states_hook(PARAM_SET, &db_param_add_set);
643 select_return_states_hook(CONTAINER, &returns_container_of);