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
);
78 if (type
&& type
->type
== SYM_STRUCT
)
83 static struct expression
*get_matching_member_expr(struct symbol
*left_type
, struct expression
*right
, struct symbol
*left_member
)
85 struct symbol
*struct_type
;
88 if (!left_member
->ident
)
91 struct_type
= get_struct_type(right
);
94 if (struct_type
!= left_type
)
97 if (right
->type
== EXPR_PREOP
&& right
->op
== '&')
98 right
= strip_expr(right
->unop
);
100 if (is_pointer(right
)) {
101 right
= deref_expression(right
);
105 return member_expression(right
, op
, left_member
->ident
);
108 static struct expression
*remove_addr(struct expression
*expr
)
110 expr
= strip_expr(expr
);
112 if (expr
->type
== EXPR_PREOP
&& expr
->op
== '&')
113 return strip_expr(expr
->unop
);
117 static struct expression
*faked_expression
;
118 struct expression
*get_faked_expression(void)
120 if (!__in_fake_assign
)
122 return faked_expression
;
125 static void __struct_members_copy(int mode
, struct expression
*faked
,
126 struct expression
*left
,
127 struct expression
*right
)
129 struct symbol
*struct_type
, *tmp
, *type
;
130 struct expression
*left_member
;
131 struct expression
*right_member
= NULL
;
132 struct expression
*assign
;
136 if (__in_fake_assign
)
138 faked_expression
= faked
;
140 left
= strip_expr(left
);
141 right
= strip_expr(right
);
143 struct_type
= get_struct_type(left
);
146 * This is not a struct assignment obviously. But this is where
147 * memcpy() is handled so it feels like a good place to add this
151 type
= get_type(left
);
152 if (!type
|| type
->type
!= SYM_BASETYPE
)
155 right
= strip_expr(right
);
156 if (right
&& right
->type
== EXPR_PREOP
&& right
->op
== '&')
157 right
= remove_addr(right
);
159 right
= unknown_value_expression(left
);
160 assign
= assign_expression(left
, right
);
162 __split_expr(assign
);
167 if (is_pointer(left
)) {
168 left
= deref_expression(left
);
172 FOR_EACH_PTR(struct_type
->symbol_list
, tmp
) {
173 type
= get_real_base_type(tmp
);
174 if (type
&& type
->type
== SYM_ARRAY
)
177 left_member
= member_expression(left
, op
, tmp
->ident
);
182 right_member
= get_matching_member_expr(struct_type
, right
, tmp
);
185 right_member
= right
;
189 right_member
= unknown_value_expression(left_member
);
190 assign
= assign_expression(left_member
, right_member
);
192 __split_expr(assign
);
194 } END_FOR_EACH_PTR(tmp
);
197 faked_expression
= NULL
;
200 void __fake_struct_member_assignments(struct expression
*expr
)
202 struct symbol
*struct_type
;
204 if (is_zero(expr
->right
))
207 struct_type
= get_struct_type(expr
->left
);
211 __struct_members_copy(COPY_NORMAL
, expr
, expr
->left
, expr
->right
);
214 static void match_memset(const char *fn
, struct expression
*expr
, void *_size_arg
)
216 struct expression
*buf
;
217 struct expression
*val
;
219 buf
= get_argument_from_call_expr(expr
->args
, 0);
220 val
= get_argument_from_call_expr(expr
->args
, 1);
222 buf
= strip_expr(buf
);
223 __struct_members_copy(COPY_MEMSET
, expr
, remove_addr(buf
), val
);
226 static void match_memcpy(const char *fn
, struct expression
*expr
, void *_arg
)
228 struct expression
*dest
;
229 struct expression
*src
;
231 dest
= get_argument_from_call_expr(expr
->args
, 0);
232 src
= get_argument_from_call_expr(expr
->args
, 1);
234 __struct_members_copy(COPY_MEMCPY
, expr
, remove_addr(dest
), remove_addr(src
));
237 static void match_memcpy_unknown(const char *fn
, struct expression
*expr
, void *_arg
)
239 struct expression
*dest
;
241 dest
= get_argument_from_call_expr(expr
->args
, 0);
242 __struct_members_copy(COPY_MEMCPY
, expr
, remove_addr(dest
), NULL
);
245 static void register_clears_param(void)
249 const char *function
;
252 if (option_project
== PROJ_NONE
)
255 snprintf(name
, 256, "%s.clears_argument", option_project_str
);
257 token
= get_tokens_file(name
);
260 if (token_type(token
) != TOKEN_STREAMBEGIN
)
263 while (token_type(token
) != TOKEN_STREAMEND
) {
264 if (token_type(token
) != TOKEN_IDENT
)
266 function
= show_ident(token
->ident
);
268 if (token_type(token
) != TOKEN_NUMBER
)
270 param
= atoi(token
->number
);
271 add_function_hook(function
, &match_memcpy_unknown
, INT_PTR(param
));
277 static void db_param_cleared(struct expression
*expr
, int param
, char *key
, char *value
)
279 struct expression
*arg
;
281 while (expr
->type
== EXPR_ASSIGNMENT
)
282 expr
= strip_expr(expr
->right
);
283 if (expr
->type
!= EXPR_CALL
)
286 arg
= get_argument_from_call_expr(expr
->args
, param
);
290 if (strcmp(value
, "0") == 0)
291 __struct_members_copy(COPY_MEMSET
, expr
, remove_addr(arg
), zero_expr());
293 __struct_members_copy(COPY_MEMCPY
, expr
, remove_addr(arg
), NULL
);
297 void register_struct_assignment(int id
)
299 add_function_hook("memset", &match_memset
, NULL
);
301 add_function_hook("memcpy", &match_memcpy
, INT_PTR(0));
302 add_function_hook("memmove", &match_memcpy
, INT_PTR(0));
304 register_clears_param();
305 select_return_states_hook(PARAM_CLEARED
, &db_param_cleared
);