user_data: kstrtoul() and friends should taint data as untrusted
[smatch.git] / smatch_struct_assignment.c
blobbfa0261532a33ec04e3c4786f6ea0db975d945cc
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 static struct symbol *get_struct_type(struct expression *expr)
65 struct symbol *type;
67 type = get_type(expr);
68 if (!type)
69 return NULL;
70 if (type->type == SYM_PTR)
71 type = get_real_base_type(type);
72 if (type && type->type == SYM_STRUCT)
73 return type;
74 return NULL;
77 static struct expression *get_matching_member_expr(struct symbol *left_type, struct expression *right, struct symbol *left_member)
79 struct symbol *struct_type;
80 int op = '.';
82 if (!left_member->ident)
83 return NULL;
85 struct_type = get_struct_type(right);
86 if (!struct_type)
87 return NULL;
88 if (struct_type != left_type)
89 return NULL;
91 if (right->type == EXPR_PREOP && right->op == '&')
92 right = strip_expr(right->unop);
94 if (is_pointer(right)) {
95 right = deref_expression(right);
96 op = '*';
99 return member_expression(right, op, left_member->ident);
102 void __struct_members_copy(int mode, struct expression *left, struct expression *right)
104 struct symbol *struct_type, *tmp, *type;
105 struct expression *left_member;
106 struct expression *right_member = NULL;
107 struct expression *assign;
108 int op = '.';
111 if (__in_fake_assign)
112 return;
114 left = strip_expr(left);
115 right = strip_expr(right);
117 struct_type = get_struct_type(left);
118 if (!struct_type)
119 return;
121 if (is_pointer(left)) {
122 left = deref_expression(left);
123 op = '*';
126 FOR_EACH_PTR(struct_type->symbol_list, tmp) {
127 type = get_real_base_type(tmp);
128 if (type && type->type == SYM_ARRAY)
129 continue;
131 left_member = member_expression(left, op, tmp->ident);
133 switch (mode) {
134 case COPY_NORMAL:
135 case COPY_MEMCPY:
136 right_member = get_matching_member_expr(struct_type, right, tmp);
137 break;
138 case COPY_MEMSET:
139 right_member = right;
140 break;
142 if (!right_member)
143 right_member = unknown_value_expression(left_member);
144 assign = assign_expression(left_member, right_member);
145 __in_fake_assign++;
146 __split_expr(assign);
147 __in_fake_assign--;
148 } END_FOR_EACH_PTR(tmp);
151 void __fake_struct_member_assignments(struct expression *expr)
153 if (is_zero(expr->right))
154 return;
156 __struct_members_copy(COPY_NORMAL, expr->left, expr->right);
159 static struct expression *remove_addr(struct expression *expr)
161 expr = strip_expr(expr);
163 if (expr->type == EXPR_PREOP && expr->op == '&')
164 return strip_expr(expr->unop);
165 return expr;
168 static void match_memset(const char *fn, struct expression *expr, void *_size_arg)
170 struct expression *buf;
171 struct expression *val;
173 buf = get_argument_from_call_expr(expr->args, 0);
174 val = get_argument_from_call_expr(expr->args, 1);
176 buf = strip_expr(buf);
177 __struct_members_copy(COPY_MEMSET, remove_addr(buf), val);
180 static void match_memcpy(const char *fn, struct expression *expr, void *_arg)
182 struct expression *dest;
183 struct expression *src;
185 dest = get_argument_from_call_expr(expr->args, 0);
186 src = get_argument_from_call_expr(expr->args, 1);
188 __struct_members_copy(COPY_MEMCPY, remove_addr(dest), remove_addr(src));
191 static void match_memcpy_unknown(const char *fn, struct expression *expr, void *_arg)
193 struct expression *dest;
195 dest = get_argument_from_call_expr(expr->args, 0);
196 __struct_members_copy(COPY_MEMCPY, remove_addr(dest), NULL);
199 static void register_clears_param(void)
201 struct token *token;
202 char name[256];
203 const char *function;
204 int param;
206 if (option_project == PROJ_NONE)
207 return;
209 snprintf(name, 256, "%s.clears_argument", option_project_str);
211 token = get_tokens_file(name);
212 if (!token)
213 return;
214 if (token_type(token) != TOKEN_STREAMBEGIN)
215 return;
216 token = token->next;
217 while (token_type(token) != TOKEN_STREAMEND) {
218 if (token_type(token) != TOKEN_IDENT)
219 return;
220 function = show_ident(token->ident);
221 token = token->next;
222 if (token_type(token) != TOKEN_NUMBER)
223 return;
224 param = atoi(token->number);
225 add_function_hook(function, &match_memcpy_unknown, INT_PTR(param));
226 token = token->next;
228 clear_token_alloc();
231 static void db_param_cleared(struct expression *expr, int param, char *key, char *value)
233 struct expression *arg;
235 while (expr->type == EXPR_ASSIGNMENT)
236 expr = strip_expr(expr->right);
237 if (expr->type != EXPR_CALL)
238 return;
240 arg = get_argument_from_call_expr(expr->args, param);
241 if (!arg)
242 return;
244 if (strcmp(value, "0") == 0)
245 __struct_members_copy(COPY_MEMSET, remove_addr(arg), zero_expr());
246 else
247 __struct_members_copy(COPY_MEMCPY, remove_addr(arg), NULL);
251 void register_struct_assignment(int id)
253 add_function_hook("memset", &match_memset, NULL);
255 add_function_hook("memcpy", &match_memcpy, INT_PTR(0));
256 add_function_hook("memmove", &match_memcpy, INT_PTR(0));
258 register_clears_param();
259 select_return_states_hook(PARAM_CLEARED, &db_param_cleared);