smatch.h: add the declaration to sm_to_arg_name()
[smatch.git] / smatch_struct_assignment.c
blob2670eca4455c40597d6545a98a5995f2f059329f
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 * I don't have a proper solution for this problem right now. I just copy one
49 * level and don't nest. It should handle limitted nesting but intelligently.
51 * The other thing is that you end up with a lot of garbage assignments where
52 * we record "x could be anything. x->y could be anything. x->y->z->a->b->c
53 * could *also* be anything!". There should be a better way to filter this
54 * useless information.
58 #include "scope.h"
59 #include "smatch.h"
60 #include "smatch_slist.h"
61 #include "smatch_extra.h"
63 enum {
64 COPY_NORMAL,
65 COPY_MEMCPY,
66 COPY_MEMSET,
69 static struct symbol *get_struct_type(struct expression *expr)
71 struct symbol *type;
73 type = get_type(expr);
74 if (!type)
75 return NULL;
76 if (type->type == SYM_PTR) {
77 type = get_real_base_type(type);
78 if (!type)
79 return NULL;
81 if (type->type == SYM_STRUCT)
82 return type;
83 if (type->type == SYM_UNION)
84 return type;
85 return NULL;
88 static struct expression *get_right_base_expr(struct symbol *left_type, struct expression *right)
90 struct symbol *struct_type;
92 if (!right)
93 return NULL;
95 struct_type = get_struct_type(right);
96 if (!struct_type)
97 return NULL;
98 if (struct_type != left_type)
99 return NULL;
101 if (right->type == EXPR_PREOP && right->op == '&')
102 right = strip_expr(right->unop);
104 if (right->type == EXPR_CALL)
105 return NULL;
107 if (is_pointer(right))
108 right = deref_expression(right);
110 return right;
113 static struct expression *remove_addr(struct expression *expr)
115 struct symbol *type;
117 expr = strip_expr(expr);
118 if (!expr)
119 return NULL;
121 if (expr->type == EXPR_PREOP && expr->op == '&')
122 return strip_expr(expr->unop);
123 type = get_type(expr);
124 if (!type)
125 return expr;
126 if (type->type != SYM_PTR && type->type != SYM_ARRAY)
127 return expr;
129 return deref_expression(expr);
132 static struct expression *faked_expression;
133 struct expression *get_faked_expression(void)
135 if (!__in_fake_assign)
136 return NULL;
137 return faked_expression;
140 static void split_fake_expr(struct expression *expr)
142 __in_fake_assign++;
143 __in_fake_struct_assign++;
144 __split_expr(expr);
145 __in_fake_struct_assign--;
146 __in_fake_assign--;
149 static void handle_non_struct_assignments(struct expression *left, struct expression *right)
151 struct symbol *type;
152 struct expression *assign;
154 type = get_type(left);
155 if (!type)
156 return;
157 if (type->type == SYM_PTR) {
158 left = deref_expression(left);
159 if (right)
160 right = deref_expression(right);
161 else
162 right = unknown_value_expression(left);
163 assign = assign_expression(left, '=', right);
164 split_fake_expr(assign);
165 return;
167 if (type->type != SYM_BASETYPE)
168 return;
169 right = strip_expr(right);
170 type = get_type(right);
171 if (!right || !type || type->type == SYM_ARRAY)
172 right = unknown_value_expression(left);
173 assign = assign_expression(left, '=', right);
174 split_fake_expr(assign);
177 static void set_inner_struct_members(int mode, struct expression *faked, struct expression *left, struct expression *right, struct symbol *member)
179 struct expression *left_member;
180 struct expression *right_member = NULL; /* silence GCC */
181 struct expression *assign;
182 struct symbol *base = get_real_base_type(member);
183 struct symbol *tmp;
185 if (member->ident) {
186 left = member_expression(left, '.', member->ident);
187 if (mode != COPY_MEMSET && right)
188 right = member_expression(right, '.', member->ident);
191 FOR_EACH_PTR(base->symbol_list, tmp) {
192 struct symbol *type;
194 type = get_real_base_type(tmp);
195 if (!type)
196 continue;
198 if (type->type == SYM_ARRAY)
199 continue;
200 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
201 set_inner_struct_members(mode, faked, left, right, tmp);
202 continue;
204 if (!tmp->ident)
205 continue;
207 left_member = member_expression(left, '.', tmp->ident);
209 switch (mode) {
210 case COPY_NORMAL:
211 case COPY_MEMCPY:
212 if (right)
213 right_member = member_expression(right, '.', tmp->ident);
214 else
215 right_member = unknown_value_expression(left_member);
216 break;
217 case COPY_MEMSET:
218 right_member = right;
219 break;
222 assign = assign_expression(left_member, '=', right_member);
223 split_fake_expr(assign);
224 } END_FOR_EACH_PTR(tmp);
227 static void __struct_members_copy(int mode, struct expression *faked,
228 struct expression *left,
229 struct expression *right)
231 struct symbol *struct_type, *tmp, *type;
232 struct expression *left_member;
233 struct expression *right_member;
234 struct expression *assign;
235 int op = '.';
238 if (__in_fake_assign)
239 return;
240 faked_expression = faked;
242 left = strip_expr(left);
243 right = strip_expr(right);
245 struct_type = get_struct_type(left);
246 if (!struct_type) {
248 * This is not a struct assignment obviously. But this is where
249 * memcpy() is handled so it feels like a good place to add this
250 * code.
252 handle_non_struct_assignments(left, right);
253 goto done;
256 if (is_pointer(left)) {
257 left = deref_expression(left);
258 op = '*';
260 if (mode != COPY_MEMSET)
261 right = get_right_base_expr(struct_type, right);
263 FOR_EACH_PTR(struct_type->symbol_list, tmp) {
264 type = get_real_base_type(tmp);
265 if (!type)
266 continue;
267 if (type->type == SYM_ARRAY)
268 continue;
270 if (type->type == SYM_UNION || type->type == SYM_STRUCT) {
271 set_inner_struct_members(mode, faked, left, right, tmp);
272 continue;
275 if (!tmp->ident)
276 continue;
278 left_member = member_expression(left, op, tmp->ident);
279 right_member = NULL;
281 switch (mode) {
282 case COPY_NORMAL:
283 case COPY_MEMCPY:
284 if (right)
285 right_member = member_expression(right, op, tmp->ident);
286 else
287 right_member = unknown_value_expression(left_member);
288 break;
289 case COPY_MEMSET:
290 right_member = right;
291 break;
293 if (!right_member) {
294 sm_perror("No right member");
295 continue;
297 assign = assign_expression(left_member, '=', right_member);
298 split_fake_expr(assign);
299 } END_FOR_EACH_PTR(tmp);
301 done:
302 faked_expression = NULL;
305 static int returns_zeroed_mem(struct expression *expr)
307 char *fn;
309 if (expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL)
310 return 0;
311 fn = expr_to_var(expr->fn);
312 if (!fn)
313 return 0;
314 if (strcmp(fn, "kcalloc") == 0)
315 return 1;
316 if (option_project == PROJ_KERNEL && strstr(fn, "zalloc"))
317 return 1;
318 return 0;
321 static int copy_containter_states(struct expression *left, struct expression *right, int offset)
323 char *left_name = NULL, *right_name = NULL;
324 struct symbol *left_sym, *right_sym;
325 struct sm_state *sm, *new_sm;
326 int ret = 0;
327 int len;
328 char buf[64];
329 char new_name[128];
331 right_name = expr_to_var_sym(right, &right_sym);
332 if (!right_name || !right_sym)
333 goto free;
334 left_name = expr_to_var_sym(left, &left_sym);
335 if (!left_name || !left_sym)
336 goto free;
338 len = snprintf(buf, sizeof(buf), "%s(-%d)", right_name, offset);
339 if (len >= sizeof(buf))
340 goto free;
342 FOR_EACH_SM(__get_cur_stree(), sm) {
343 if (sm->sym != right_sym)
344 continue;
345 if (strncmp(sm->name, buf, len) != 0)
346 continue;
347 snprintf(new_name, sizeof(new_name), "%s%s", left_name, sm->name + len);
348 new_sm = clone_sm(sm);
349 new_sm->name = alloc_sname(new_name);
350 new_sm->sym = left_sym;
351 __set_sm(new_sm);
352 ret = 1;
353 } END_FOR_EACH_SM(sm);
354 free:
355 free_string(left_name);
356 free_string(right_name);
357 return ret;
360 static int handle_param_offsets(struct expression *expr)
362 struct expression *right;
363 sval_t sval;
365 right = strip_expr(expr->right);
367 if (right->type != EXPR_BINOP || right->op != '-')
368 return 0;
370 if (!get_value(right->right, &sval))
371 return 0;
373 right = get_assigned_expr(right->left);
374 if (!right)
375 return 0;
376 return copy_containter_states(expr->left, right, sval.value);
379 static void returns_container_of(struct expression *expr, int param, char *key, char *value)
381 struct expression *call, *arg;
382 int offset;
384 if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
385 return;
386 call = strip_expr(expr->right);
387 if (call->type != EXPR_CALL)
388 return;
389 if (param != -1)
390 return;
391 param = atoi(key);
392 offset = atoi(value);
394 arg = get_argument_from_call_expr(call->args, param);
395 if (!arg)
396 return;
398 copy_containter_states(expr->left, arg, -offset);
401 void __fake_struct_member_assignments(struct expression *expr)
403 struct symbol *left_type;
405 if (expr->op != '=')
406 return;
408 if (expr_is_zero(expr->right))
409 return;
411 left_type = get_type(expr->left);
412 if (!left_type ||
413 (left_type->type != SYM_PTR &&
414 left_type->type != SYM_STRUCT))
415 return;
417 if (handle_param_offsets(expr))
418 return;
420 if (returns_zeroed_mem(expr->right))
421 __struct_members_copy(COPY_MEMSET, expr, expr->left, zero_expr());
422 else
423 __struct_members_copy(COPY_NORMAL, expr, expr->left, expr->right);
426 static void match_memset(const char *fn, struct expression *expr, void *_size_arg)
428 struct expression *buf;
429 struct expression *val;
431 buf = get_argument_from_call_expr(expr->args, 0);
432 val = get_argument_from_call_expr(expr->args, 1);
434 buf = strip_expr(buf);
435 __struct_members_copy(COPY_MEMSET, expr, remove_addr(buf), val);
438 static void match_memcpy(const char *fn, struct expression *expr, void *_arg)
440 struct expression *dest;
441 struct expression *src;
443 dest = get_argument_from_call_expr(expr->args, 0);
444 src = get_argument_from_call_expr(expr->args, 1);
446 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), remove_addr(src));
449 static void match_memdup(const char *fn, struct expression *call_expr,
450 struct expression *expr, void *_unused)
452 struct expression *left, *right, *arg;
454 if (!expr || expr->type != EXPR_ASSIGNMENT)
455 return;
457 left = strip_expr(expr->left);
458 right = strip_expr(expr->right);
460 if (right->type != EXPR_CALL)
461 return;
462 arg = get_argument_from_call_expr(right->args, 0);
463 __struct_members_copy(COPY_MEMCPY, expr, left, arg);
466 static void match_memcpy_unknown(const char *fn, struct expression *expr, void *_arg)
468 struct expression *dest;
470 dest = get_argument_from_call_expr(expr->args, 0);
471 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), NULL);
474 static void match_sscanf(const char *fn, struct expression *expr, void *unused)
476 struct expression *arg;
477 int i;
479 i = -1;
480 FOR_EACH_PTR(expr->args, arg) {
481 if (++i < 2)
482 continue;
483 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(arg), NULL);
484 } END_FOR_EACH_PTR(arg);
487 static void unop_expr(struct expression *expr)
489 if (expr->op != SPECIAL_INCREMENT &&
490 expr->op != SPECIAL_DECREMENT)
491 return;
493 if (!is_pointer(expr))
494 return;
495 faked_expression = expr;
496 __struct_members_copy(COPY_MEMCPY, expr, expr->unop, NULL);
497 faked_expression = NULL;
500 static void register_clears_param(void)
502 struct token *token;
503 char name[256];
504 const char *function;
505 int param;
507 if (option_project == PROJ_NONE)
508 return;
510 snprintf(name, 256, "%s.clears_argument", option_project_str);
512 token = get_tokens_file(name);
513 if (!token)
514 return;
515 if (token_type(token) != TOKEN_STREAMBEGIN)
516 return;
517 token = token->next;
518 while (token_type(token) != TOKEN_STREAMEND) {
519 if (token_type(token) != TOKEN_IDENT)
520 return;
521 function = show_ident(token->ident);
522 token = token->next;
523 if (token_type(token) != TOKEN_NUMBER)
524 return;
525 param = atoi(token->number);
526 add_function_hook(function, &match_memcpy_unknown, INT_PTR(param));
527 token = token->next;
529 clear_token_alloc();
532 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
534 struct expression *arg;
536 while (expr->type == EXPR_ASSIGNMENT)
537 expr = strip_expr(expr->right);
538 if (expr->type != EXPR_CALL)
539 return;
542 * FIXME: __struct_members_copy() requires an expression but
543 * get_variable_from_key() returns a name/sym pair so that doesn't
544 * work here.
546 if (strcmp(key, "$") != 0)
547 return;
549 arg = get_argument_from_call_expr(expr->args, param);
550 if (!arg)
551 return;
553 if (strcmp(value, "0") == 0)
554 __struct_members_copy(COPY_MEMSET, expr, remove_addr(arg), zero_expr());
555 else
556 __struct_members_copy(COPY_MEMCPY, expr, remove_addr(arg), NULL);
559 void register_struct_assignment(int id)
561 add_function_hook("memset", &match_memset, NULL);
562 add_function_hook("__memset", &match_memset, NULL);
564 add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
565 add_function_hook("memmove", &match_memcpy, INT_PTR(0));
566 add_function_hook("__memcpy", &match_memcpy, INT_PTR(0));
567 add_function_hook("__memmove", &match_memcpy, INT_PTR(0));
569 if (option_project == PROJ_KERNEL)
570 return_implies_state_sval("kmemdup", valid_ptr_min_sval, valid_ptr_max_sval, &match_memdup, NULL);
572 add_function_hook("sscanf", &match_sscanf, NULL);
574 add_hook(&unop_expr, OP_HOOK);
575 register_clears_param();
576 select_return_states_hook(PARAM_CLEARED, &db_param_cleared);
578 select_return_states_hook(CONTAINER, &returns_container_of);