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;
25 * That's equivalent to saying:
30 * Turning an assignment like that into a bunch of small fake assignments is
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:
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.
60 #include "smatch_slist.h"
61 #include "smatch_extra.h"
69 static struct symbol
*get_struct_type(struct expression
*expr
)
73 type
= get_type(expr
);
76 if (type
->type
== SYM_PTR
) {
77 type
= get_real_base_type(type
);
81 if (type
->type
== SYM_STRUCT
)
83 if (type
->type
== SYM_UNION
)
88 static struct expression
*get_right_base_expr(struct symbol
*left_type
, struct expression
*right
)
90 struct symbol
*struct_type
;
95 struct_type
= get_struct_type(right
);
98 if (struct_type
!= left_type
)
101 if (right
->type
== EXPR_PREOP
&& right
->op
== '&')
102 right
= strip_expr(right
->unop
);
104 if (right
->type
== EXPR_CALL
)
107 if (is_pointer(right
))
108 right
= deref_expression(right
);
113 static struct expression
*remove_addr(struct expression
*expr
)
117 expr
= strip_expr(expr
);
121 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
122 return strip_expr(expr
->unop
);
123 type
= get_type(expr
);
126 if (type
->type
!= SYM_PTR
&& type
->type
!= SYM_ARRAY
)
129 return deref_expression(expr
);
132 static struct expression
*faked_expression
;
133 struct expression
*get_faked_expression(void)
135 if (!__in_fake_assign
)
137 return faked_expression
;
140 static void split_fake_expr(struct expression
*expr
)
143 __in_fake_struct_assign
++;
145 __in_fake_struct_assign
--;
149 static void handle_non_struct_assignments(struct expression
*left
, struct expression
*right
)
152 struct expression
*assign
;
154 while (right
&& right
->type
== EXPR_ASSIGNMENT
)
155 right
= strip_parens(right
->left
);
157 type
= get_type(left
);
160 if (type
->type
== SYM_PTR
) {
161 left
= deref_expression(left
);
163 right
= deref_expression(right
);
165 right
= unknown_value_expression(left
);
166 assign
= assign_expression(left
, '=', right
);
167 split_fake_expr(assign
);
170 if (type
->type
!= SYM_BASETYPE
)
172 right
= strip_expr(right
);
173 type
= get_type(right
);
174 if (!right
|| !type
|| type
->type
== SYM_ARRAY
)
175 right
= unknown_value_expression(left
);
176 assign
= assign_expression(left
, '=', right
);
177 split_fake_expr(assign
);
180 static void set_inner_struct_members(int mode
, struct expression
*faked
, struct expression
*left
, struct expression
*right
, struct symbol
*member
)
182 struct expression
*left_member
;
183 struct expression
*right_member
= NULL
; /* silence GCC */
184 struct expression
*assign
;
185 struct symbol
*base
= get_real_base_type(member
);
189 left
= member_expression(left
, '.', member
->ident
);
190 if (mode
!= COPY_MEMSET
&& right
)
191 right
= member_expression(right
, '.', member
->ident
);
194 FOR_EACH_PTR(base
->symbol_list
, tmp
) {
197 type
= get_real_base_type(tmp
);
201 if (type
->type
== SYM_ARRAY
)
203 if (type
->type
== SYM_UNION
|| type
->type
== SYM_STRUCT
) {
204 set_inner_struct_members(mode
, faked
, left
, right
, tmp
);
210 left_member
= member_expression(left
, '.', tmp
->ident
);
216 right_member
= member_expression(right
, '.', tmp
->ident
);
218 right_member
= unknown_value_expression(left_member
);
221 right_member
= right
;
225 assign
= assign_expression(left_member
, '=', right_member
);
226 split_fake_expr(assign
);
227 } END_FOR_EACH_PTR(tmp
);
230 static void __struct_members_copy(int mode
, struct expression
*faked
,
231 struct expression
*left
,
232 struct expression
*right
)
234 struct symbol
*struct_type
, *tmp
, *type
;
235 struct expression
*left_member
;
236 struct expression
*right_member
;
237 struct expression
*assign
;
240 if (__in_fake_assign
)
242 faked_expression
= faked
;
244 left
= strip_expr(left
);
245 right
= strip_expr(right
);
247 if (left
->type
== EXPR_PREOP
&& left
->op
== '*' && is_pointer(left
))
248 left
= preop_expression(left
, '(');
250 struct_type
= get_struct_type(left
);
253 * This is not a struct assignment obviously. But this is where
254 * memcpy() is handled so it feels like a good place to add this
257 handle_non_struct_assignments(left
, right
);
261 if (is_pointer(left
)) {
262 left
= deref_expression(left
);
265 if (mode
!= COPY_MEMSET
)
266 right
= get_right_base_expr(struct_type
, right
);
268 FOR_EACH_PTR(struct_type
->symbol_list
, tmp
) {
269 type
= get_real_base_type(tmp
);
272 if (type
->type
== SYM_ARRAY
)
275 if (type
->type
== SYM_UNION
|| type
->type
== SYM_STRUCT
) {
276 set_inner_struct_members(mode
, faked
, left
, right
, tmp
);
283 left_member
= member_expression(left
, op
, tmp
->ident
);
290 right_member
= member_expression(right
, op
, tmp
->ident
);
292 right_member
= unknown_value_expression(left_member
);
295 right_member
= right
;
299 sm_perror("No right member");
302 assign
= assign_expression(left_member
, '=', right_member
);
303 split_fake_expr(assign
);
304 } END_FOR_EACH_PTR(tmp
);
307 faked_expression
= NULL
;
310 static int returns_zeroed_mem(struct expression
*expr
)
314 if (expr
->type
!= EXPR_CALL
|| expr
->fn
->type
!= EXPR_SYMBOL
)
316 fn
= expr_to_var(expr
->fn
);
319 if (strcmp(fn
, "kcalloc") == 0)
321 if (option_project
== PROJ_KERNEL
&& strstr(fn
, "zalloc"))
326 static int copy_containter_states(struct expression
*left
, struct expression
*right
, int offset
)
328 char *left_name
= NULL
, *right_name
= NULL
;
329 struct symbol
*left_sym
, *right_sym
;
330 struct sm_state
*sm
, *new_sm
;
336 right_name
= expr_to_var_sym(right
, &right_sym
);
337 if (!right_name
|| !right_sym
)
339 left_name
= expr_to_var_sym(left
, &left_sym
);
340 if (!left_name
|| !left_sym
)
343 len
= snprintf(buf
, sizeof(buf
), "%s(-%d)", right_name
, offset
);
344 if (len
>= sizeof(buf
))
347 FOR_EACH_SM(__get_cur_stree(), sm
) {
348 if (sm
->sym
!= right_sym
)
350 if (strncmp(sm
->name
, buf
, len
) != 0)
352 snprintf(new_name
, sizeof(new_name
), "%s%s", left_name
, sm
->name
+ len
);
353 new_sm
= clone_sm(sm
);
354 new_sm
->name
= alloc_sname(new_name
);
355 new_sm
->sym
= left_sym
;
358 } END_FOR_EACH_SM(sm
);
360 free_string(left_name
);
361 free_string(right_name
);
365 static int handle_param_offsets(struct expression
*expr
)
367 struct expression
*right
;
370 right
= strip_expr(expr
->right
);
372 if (right
->type
!= EXPR_BINOP
|| right
->op
!= '-')
375 if (!get_value(right
->right
, &sval
))
378 right
= get_assigned_expr(right
->left
);
381 return copy_containter_states(expr
->left
, right
, sval
.value
);
384 static void returns_container_of(struct expression
*expr
, int param
, char *key
, char *value
)
386 struct expression
*call
, *arg
;
389 if (expr
->type
!= EXPR_ASSIGNMENT
|| expr
->op
!= '=')
391 call
= strip_expr(expr
->right
);
392 if (call
->type
!= EXPR_CALL
)
397 offset
= atoi(value
);
399 arg
= get_argument_from_call_expr(call
->args
, param
);
403 copy_containter_states(expr
->left
, arg
, -offset
);
406 void __fake_struct_member_assignments(struct expression
*expr
)
408 struct symbol
*left_type
;
413 if (expr_is_zero(expr
->right
))
416 left_type
= get_type(expr
->left
);
418 (left_type
->type
!= SYM_PTR
&&
419 left_type
->type
!= SYM_STRUCT
))
422 if (handle_param_offsets(expr
))
425 if (returns_zeroed_mem(expr
->right
))
426 __struct_members_copy(COPY_MEMSET
, expr
, expr
->left
, zero_expr());
428 __struct_members_copy(COPY_NORMAL
, expr
, expr
->left
, expr
->right
);
431 static void match_memset(const char *fn
, struct expression
*expr
, void *_size_arg
)
433 struct expression
*buf
;
434 struct expression
*val
;
436 buf
= get_argument_from_call_expr(expr
->args
, 0);
437 val
= get_argument_from_call_expr(expr
->args
, 1);
439 buf
= strip_expr(buf
);
440 __struct_members_copy(COPY_MEMSET
, expr
, remove_addr(buf
), val
);
443 static void match_memcpy(const char *fn
, struct expression
*expr
, void *_arg
)
445 struct expression
*dest
;
446 struct expression
*src
;
448 dest
= get_argument_from_call_expr(expr
->args
, 0);
449 src
= get_argument_from_call_expr(expr
->args
, 1);
451 __struct_members_copy(COPY_MEMCPY
, expr
, remove_addr(dest
), remove_addr(src
));
454 static void match_memdup(const char *fn
, struct expression
*call_expr
,
455 struct expression
*expr
, void *_unused
)
457 struct expression
*left
, *right
, *arg
;
459 if (!expr
|| expr
->type
!= EXPR_ASSIGNMENT
)
462 left
= strip_expr(expr
->left
);
463 right
= strip_expr(expr
->right
);
465 if (right
->type
!= EXPR_CALL
)
467 arg
= get_argument_from_call_expr(right
->args
, 0);
468 __struct_members_copy(COPY_MEMCPY
, expr
, left
, arg
);
471 static void match_memcpy_unknown(const char *fn
, struct expression
*expr
, void *_arg
)
473 struct expression
*dest
;
475 dest
= get_argument_from_call_expr(expr
->args
, 0);
476 __struct_members_copy(COPY_MEMCPY
, expr
, remove_addr(dest
), NULL
);
479 static void match_sscanf(const char *fn
, struct expression
*expr
, void *unused
)
481 struct expression
*arg
;
485 FOR_EACH_PTR(expr
->args
, arg
) {
488 __struct_members_copy(COPY_MEMCPY
, expr
, remove_addr(arg
), NULL
);
489 } END_FOR_EACH_PTR(arg
);
492 static void unop_expr(struct expression
*expr
)
494 if (expr
->op
!= SPECIAL_INCREMENT
&&
495 expr
->op
!= SPECIAL_DECREMENT
)
498 if (!is_pointer(expr
))
500 faked_expression
= expr
;
501 __struct_members_copy(COPY_MEMCPY
, expr
, expr
->unop
, NULL
);
502 faked_expression
= NULL
;
505 static void register_clears_param(void)
509 const char *function
;
512 if (option_project
== PROJ_NONE
)
515 snprintf(name
, 256, "%s.clears_argument", option_project_str
);
517 token
= get_tokens_file(name
);
520 if (token_type(token
) != TOKEN_STREAMBEGIN
)
523 while (token_type(token
) != TOKEN_STREAMEND
) {
524 if (token_type(token
) != TOKEN_IDENT
)
526 function
= show_ident(token
->ident
);
528 if (token_type(token
) != TOKEN_NUMBER
)
530 param
= atoi(token
->number
);
531 add_function_hook(function
, &match_memcpy_unknown
, INT_PTR(param
));
537 static void db_param_cleared(struct expression
*expr
, int param
, char *key
, char *value
)
539 struct expression
*arg
;
541 while (expr
->type
== EXPR_ASSIGNMENT
)
542 expr
= strip_expr(expr
->right
);
543 if (expr
->type
!= EXPR_CALL
)
547 * FIXME: __struct_members_copy() requires an expression but
548 * get_variable_from_key() returns a name/sym pair so that doesn't
551 if (strcmp(key
, "$") != 0)
554 arg
= get_argument_from_call_expr(expr
->args
, param
);
558 if (strcmp(value
, "0") == 0)
559 __struct_members_copy(COPY_MEMSET
, expr
, remove_addr(arg
), zero_expr());
561 __struct_members_copy(COPY_MEMCPY
, expr
, remove_addr(arg
), NULL
);
564 void register_struct_assignment(int id
)
566 add_function_hook("memset", &match_memset
, NULL
);
567 add_function_hook("__memset", &match_memset
, NULL
);
569 add_function_hook("memcpy", &match_memcpy
, INT_PTR(0));
570 add_function_hook("memmove", &match_memcpy
, INT_PTR(0));
571 add_function_hook("__memcpy", &match_memcpy
, INT_PTR(0));
572 add_function_hook("__memmove", &match_memcpy
, INT_PTR(0));
574 if (option_project
== PROJ_KERNEL
)
575 return_implies_state_sval("kmemdup", valid_ptr_min_sval
, valid_ptr_max_sval
, &match_memdup
, NULL
);
577 add_function_hook("sscanf", &match_sscanf
, NULL
);
579 add_hook(&unop_expr
, OP_HOOK
);
580 register_clears_param();
581 select_return_states_hook(PARAM_CLEARED
, &db_param_cleared
);
583 select_return_states_hook(CONTAINER
, &returns_container_of
);