modification_hooks: handle PARAM_SET earlier
[smatch.git] / smatch_constraints_required.c
blob4fa0515a39623c2a8b3f420189fbd00868aa8083
1 /*
2 * Copyright (C) 2017 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
18 #include "smatch.h"
19 #include "smatch_extra.h"
21 static int my_id;
23 struct allocator {
24 const char *func;
25 int param;
26 int param2;
29 static struct allocator generic_allocator_table[] = {
30 {"malloc", 0},
31 {"memdup", 1},
32 {"realloc", 1},
35 static struct allocator kernel_allocator_table[] = {
36 {"kmalloc", 0},
37 {"kzalloc", 0},
38 {"vmalloc", 0},
39 {"__vmalloc", 0},
40 {"vzalloc", 0},
41 {"sock_kmalloc", 1},
42 {"kmemdup", 1},
43 {"kmemdup_user", 1},
44 {"dma_alloc_attrs", 1},
45 {"pci_alloc_consistent", 1},
46 {"pci_alloc_coherent", 1},
47 {"devm_kmalloc", 1},
48 {"devm_kzalloc", 1},
49 {"krealloc", 1},
52 static struct allocator calloc_table[] = {
53 {"calloc", 0, 1},
54 {"kcalloc", 0, 1},
57 static int bytes_per_element(struct expression *expr)
59 struct symbol *type;
61 type = get_type(expr);
62 if (!type)
63 return 0;
65 if (type->type != SYM_PTR && type->type != SYM_ARRAY)
66 return 0;
68 type = get_base_type(type);
69 return type_bytes(type);
72 static void save_constraint_required(struct expression *pointer, int op, struct expression *constraint)
74 char *data, *limit;
76 data = get_constraint_str(pointer);
77 if (!data)
78 return;
80 limit = get_constraint_str(constraint);
81 if (!limit) {
82 // FIXME deal with <= also
83 if (op == '<')
84 set_state_expr(my_id, constraint, alloc_state_expr(pointer));
85 goto free_data;
88 sql_save_constraint_required(data, op, limit);
90 free_string(limit);
91 free_data:
92 free_string(data);
95 static void match_alloc_helper(struct expression *pointer, struct expression *size)
97 struct expression *tmp;
98 sval_t sval;
99 int cnt = 0;
101 pointer = strip_expr(pointer);
102 size = strip_expr(size);
103 if (!size || !pointer)
104 return;
106 while ((tmp = get_assigned_expr(size))) {
107 size = strip_expr(tmp);
108 if (cnt++ > 5)
109 break;
112 if (size->type == EXPR_BINOP && size->op == '*') {
113 struct expression *mult_left, *mult_right;
115 mult_left = strip_expr(size->left);
116 mult_right = strip_expr(size->right);
118 if (get_implied_value(mult_left, &sval) &&
119 sval.value == bytes_per_element(pointer))
120 size = mult_right;
121 else if (get_implied_value(mult_right, &sval) &&
122 sval.value == bytes_per_element(pointer))
123 size = mult_left;
124 else
125 return;
128 if (size->type == EXPR_BINOP && size->op == '+' &&
129 get_implied_value(size->right, &sval) &&
130 sval.value == 1)
131 save_constraint_required(pointer, SPECIAL_LTE, size->left);
132 else
133 save_constraint_required(pointer, '<', size);
136 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
138 int size_arg = PTR_INT(_size_arg);
139 struct expression *call, *arg;
141 call = strip_expr(expr->right);
142 arg = get_argument_from_call_expr(call->args, size_arg);
144 match_alloc_helper(expr->left, arg);
147 static void match_calloc(const char *fn, struct expression *expr, void *_start_arg)
149 struct expression *pointer, *call, *size;
150 struct expression *count = NULL;
151 int start_arg = PTR_INT(_start_arg);
152 sval_t sval;
154 pointer = strip_expr(expr->left);
155 call = strip_expr(expr->right);
157 size = get_argument_from_call_expr(call->args, start_arg);
158 if (get_implied_value(size, &sval) &&
159 sval.value == bytes_per_element(pointer))
160 count = get_argument_from_call_expr(call->args, start_arg + 1);
161 else {
162 size = get_argument_from_call_expr(call->args, start_arg + 1);
163 if (get_implied_value(size, &sval) &&
164 sval.value == bytes_per_element(pointer))
165 count = get_argument_from_call_expr(call->args, start_arg);
168 if (!count)
169 return;
171 save_constraint_required(pointer, '<', count);
174 static void add_allocation_function(const char *func, void *call_back, int param)
176 add_function_assign_hook(func, call_back, INT_PTR(param));
179 static void match_assign_size(struct expression *expr)
181 struct smatch_state *state;
182 char *data, *limit;
184 state = get_state_expr(my_id, expr->right);
185 if (!state || !state->data)
186 return;
188 data = get_constraint_str(state->data);
189 if (!data)
190 return;
192 limit = get_constraint_str(expr->left);
193 if (!limit)
194 goto free_data;
196 sql_save_constraint_required(data, '<', limit);
198 free_string(limit);
199 free_data:
200 free_string(data);
203 static void match_assign_data(struct expression *expr)
205 struct expression *right, *arg, *tmp;
206 int i;
207 int size_arg;
208 int size_arg2 = -1;
210 if (expr->op != '=')
211 return;
213 /* Direct calls are handled else where (for now at least) */
214 tmp = get_assigned_expr(expr->right);
215 if (!tmp)
216 return;
218 right = strip_expr(tmp);
219 if (right->type != EXPR_CALL)
220 return;
222 if (right->fn->type != EXPR_SYMBOL ||
223 !right->fn->symbol ||
224 !right->fn->symbol->ident)
225 return;
227 for (i = 0; i < ARRAY_SIZE(generic_allocator_table); i++) {
228 if (strcmp(right->fn->symbol->ident->name,
229 generic_allocator_table[i].func) == 0) {
230 size_arg = generic_allocator_table[i].param;
231 goto found;
235 if (option_project != PROJ_KERNEL)
236 return;
238 for (i = 0; i < ARRAY_SIZE(kernel_allocator_table); i++) {
239 if (strcmp(right->fn->symbol->ident->name,
240 kernel_allocator_table[i].func) == 0) {
241 size_arg = kernel_allocator_table[i].param;
242 goto found;
246 for (i = 0; i < ARRAY_SIZE(calloc_table); i++) {
247 if (strcmp(right->fn->symbol->ident->name,
248 calloc_table[i].func) == 0) {
249 size_arg = calloc_table[i].param;
250 size_arg2 = calloc_table[i].param2;
251 goto found;
255 return;
257 found:
258 arg = get_argument_from_call_expr(right->args, size_arg);
259 match_alloc_helper(expr->left, arg);
260 if (size_arg2 == -1)
261 return;
262 arg = get_argument_from_call_expr(right->args, size_arg2);
263 match_alloc_helper(expr->left, arg);
266 static void match_assign_ARRAY_SIZE(struct expression *expr)
268 struct expression *array;
269 char *data, *limit;
270 const char *macro;
272 macro = get_macro_name(expr->right->pos);
273 if (!macro || strcmp(macro, "ARRAY_SIZE") != 0)
274 return;
275 array = strip_expr(expr->right);
276 if (array->type != EXPR_BINOP || array->op != '+')
277 return;
278 array = strip_expr(array->left);
279 if (array->type != EXPR_BINOP || array->op != '/')
280 return;
281 array = strip_expr(array->left);
282 if (array->type != EXPR_SIZEOF)
283 return;
284 array = strip_expr(array->cast_expression);
285 if (array->type != EXPR_PREOP || array->op != '*')
286 return;
287 array = strip_expr(array->unop);
289 data = get_constraint_str(array);
290 limit = get_constraint_str(expr->left);
291 if (!data || !limit)
292 goto free;
294 sql_save_constraint_required(data, '<', limit);
296 free:
297 free_string(data);
298 free_string(limit);
301 void register_constraints_required(int id)
303 my_id = id;
305 add_hook(&match_assign_size, ASSIGNMENT_HOOK);
306 add_hook(&match_assign_data, ASSIGNMENT_HOOK);
308 add_hook(&match_assign_ARRAY_SIZE, ASSIGNMENT_HOOK);
309 add_hook(&match_assign_ARRAY_SIZE, GLOBAL_ASSIGNMENT_HOOK);
311 add_allocation_function("malloc", &match_alloc, 0);
312 add_allocation_function("memdup", &match_alloc, 1);
313 add_allocation_function("realloc", &match_alloc, 1);
314 add_allocation_function("realloc", &match_calloc, 0);
315 if (option_project == PROJ_KERNEL) {
316 add_allocation_function("kmalloc", &match_alloc, 0);
317 add_allocation_function("kzalloc", &match_alloc, 0);
318 add_allocation_function("vmalloc", &match_alloc, 0);
319 add_allocation_function("__vmalloc", &match_alloc, 0);
320 add_allocation_function("vzalloc", &match_alloc, 0);
321 add_allocation_function("sock_kmalloc", &match_alloc, 1);
322 add_allocation_function("kmemdup", &match_alloc, 1);
323 add_allocation_function("kmemdup_user", &match_alloc, 1);
324 add_allocation_function("dma_alloc_attrs", &match_alloc, 1);
325 add_allocation_function("pci_alloc_consistent", &match_alloc, 1);
326 add_allocation_function("pci_alloc_coherent", &match_alloc, 1);
327 add_allocation_function("devm_kmalloc", &match_alloc, 1);
328 add_allocation_function("devm_kzalloc", &match_alloc, 1);
329 add_allocation_function("kcalloc", &match_calloc, 0);
330 add_allocation_function("devm_kcalloc", &match_calloc, 1);
331 add_allocation_function("krealloc", &match_alloc, 1);