buf_size: do cross function analysis
[smatch.git] / smatch_buf_size.c
blobc0d96c165eb2b2f494d6e97f3e2d4d9bde3b0459
1 /*
2 * smatch/smatch_buf_size.c
4 * Copyright (C) 2010 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdlib.h>
11 #include <errno.h>
12 #include "parse.h"
13 #include "smatch.h"
14 #include "smatch_slist.h"
15 #include "smatch_extra.h"
18 * This check has two smatch IDs.
19 * my_size_id - used to store the size of arrays.
20 * my_strlen_id - track the strlen() of buffers.
23 static int my_size_id;
24 static int my_strlen_id;
26 struct limiter {
27 int buf_arg;
28 int limit_arg;
30 static struct limiter b0_l2 = {0, 2};
32 static _Bool params_set[32];
34 static int db_callback(void *unused, int argc, char **argv, char **azColName)
36 struct symbol *arg;
37 unsigned int param;
38 unsigned int size;
39 int i;
40 int dummy = 0;
42 errno = 0;
43 param = strtoul(argv[0], NULL, 10);
44 size = strtoul(argv[1], NULL, 10);
45 if (errno)
46 return dummy;
48 if (param >= ARRAY_SIZE(params_set))
49 return dummy;
50 if (params_set[param])
51 return dummy;
52 params_set[param] = 1;
54 i = 0;
55 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
56 if (i == param && arg->ident->name) {
57 sm_msg("name = '%s'", arg->ident->name);
58 set_state(my_size_id, arg->ident->name, arg, alloc_state_num(size));
60 i++;
61 } END_FOR_EACH_PTR(arg);
63 return dummy;
66 static void match_function_def(struct symbol *sym)
68 if (!sym || !sym->ident || !sym->ident->name)
69 return;
71 if (sym->ctype.modifiers & MOD_STATIC) {
72 run_sql(db_callback,
73 "select distinct parameter, size from buf_size "
74 "where file = '%s' and function = '%s' "
75 "order by size desc;",
76 get_filename(), sym->ident->name);
77 } else {
78 run_sql(db_callback,
79 "select distinct parameter, size from buf_size "
80 "where function = '%s' "
81 "order by size desc;",
82 sym->ident->name);
86 static int get_initializer_size(struct expression *expr)
88 switch (expr->type) {
89 case EXPR_STRING:
90 return expr->string->length;
91 case EXPR_INITIALIZER: {
92 struct expression *tmp;
93 int i = 0;
94 int max = 0;
96 FOR_EACH_PTR(expr->expr_list, tmp) {
97 if (tmp->type == EXPR_INDEX && tmp->idx_to > max)
98 max = tmp->idx_to;
99 i++;
100 } END_FOR_EACH_PTR(tmp);
101 if (max)
102 return max + 1;
103 return i;
105 case EXPR_SYMBOL:
106 return get_array_size(expr);
108 return 0;
111 static float get_cast_ratio(struct expression *unstripped)
113 struct expression *start_expr;
114 struct symbol *start_type;
115 struct symbol *end_type;
116 int start_bytes = 0;
117 int end_bytes = 0;
119 start_expr = strip_expr(unstripped);
120 start_type = get_type(start_expr);
121 end_type = get_type(unstripped);
122 if (!start_type || !end_type)
123 return 1;
125 if (start_type->type == SYM_PTR)
126 start_bytes = (get_base_type(start_type))->ctype.alignment;
127 if (start_type->type == SYM_ARRAY)
128 start_bytes = (get_base_type(start_type))->bit_size / 8;
129 if (end_type->type == SYM_PTR)
130 end_bytes = (get_base_type(end_type))->ctype.alignment;
131 if (end_type->type == SYM_ARRAY)
132 end_bytes = (get_base_type(end_type))->bit_size / 8;
134 if (!start_bytes || !end_bytes)
135 return 1;
136 return start_bytes / end_bytes;
139 int get_array_size(struct expression *expr)
141 struct symbol *tmp;
142 struct smatch_state *state;
143 int ret = 0;
144 float cast_ratio;
145 long long len;
147 if (expr->type == EXPR_STRING)
148 return expr->string->length;
150 cast_ratio = get_cast_ratio(expr);
151 expr = strip_expr(expr);
152 tmp = get_type(expr);
153 if (!tmp)
154 return 0;
156 if (tmp->type == SYM_ARRAY) {
157 ret = get_expression_value(tmp->array_size);
158 /* Dynamically sized array are -1 in sparse */
159 if (ret < 0)
160 return 0;
161 /* People put one element arrays on the end of structs */
162 if (ret == 1)
163 return 0;
164 if (ret)
165 return ret * cast_ratio;
168 state = get_state_expr(my_size_id, expr);
169 if (state == &merged)
170 return 0;
171 if (state && state->data) {
172 if (tmp->type == SYM_PTR)
173 tmp = get_base_type(tmp);
174 if (!tmp->ctype.alignment)
175 return 0;
176 ret = (int)state->data / tmp->ctype.alignment;
177 return ret * cast_ratio;
180 if (expr->type == EXPR_SYMBOL && expr->symbol->initializer) {
181 if (expr->symbol->initializer != expr) /* int a = a; */
182 return get_initializer_size(expr->symbol->initializer) * cast_ratio;
185 state = get_state_expr(my_strlen_id, expr);
186 if (!state || !state->data)
187 return 0;
188 if (get_implied_max((struct expression *)state->data, &len))
189 return len + 1; /* add one because strlen doesn't include the NULL */
190 return 0;
193 int get_array_size_bytes(struct expression *expr)
195 struct symbol *tmp;
196 int array_size;
197 int element_size;
199 if (expr->type == EXPR_STRING)
200 return expr->string->length;
202 tmp = get_type(expr);
203 if (!tmp)
204 return 0;
206 if (tmp->type == SYM_ARRAY) {
207 tmp = get_base_type(tmp);
208 element_size = tmp->bit_size / 8;
209 } else if (tmp->type == SYM_PTR) {
210 tmp = get_base_type(tmp);
211 element_size = tmp->ctype.alignment;
212 } else {
213 return 0;
215 array_size = get_array_size(expr);
216 return array_size * element_size;
219 static void match_strlen_condition(struct expression *expr)
221 struct expression *left;
222 struct expression *right;
223 struct expression *str;
224 int strlen_left = 0;
225 int strlen_right = 0;
226 long long val;
227 struct smatch_state *true_state = NULL;
228 struct smatch_state *false_state = NULL;
230 if (expr->type != EXPR_COMPARE)
231 return;
232 left = strip_expr(expr->left);
233 right = strip_expr(expr->right);
235 if (left->type == EXPR_CALL && sym_name_is("strlen", left->fn)) {
236 str = get_argument_from_call_expr(left->args, 0);
237 strlen_left = 1;
239 if (right->type == EXPR_CALL && sym_name_is("strlen", right->fn)) {
240 str = get_argument_from_call_expr(right->args, 0);
241 strlen_right = 1;
244 if (!strlen_left && !strlen_right)
245 return;
246 if (strlen_left && strlen_right)
247 return;
249 if (strlen_left) {
250 if (!get_value(right, &val))
251 return;
253 if (strlen_right) {
254 if (!get_value(left, &val))
255 return;
258 if (expr->op == SPECIAL_EQUAL) {
259 set_true_false_states_expr(my_size_id, str, alloc_state_num(val + 1), NULL);
260 return;
262 if (expr->op == SPECIAL_NOTEQUAL) {
263 set_true_false_states_expr(my_size_id, str, NULL, alloc_state_num(val + 1));
264 return;
267 switch (expr->op) {
268 case '<':
269 case SPECIAL_UNSIGNED_LT:
270 if (strlen_left)
271 true_state = alloc_state_num(val);
272 else
273 false_state = alloc_state_num(val + 1);
274 break;
275 case SPECIAL_LTE:
276 case SPECIAL_UNSIGNED_LTE:
277 if (strlen_left)
278 true_state = alloc_state_num(val + 1);
279 else
280 false_state = alloc_state_num(val);
281 break;
282 case SPECIAL_GTE:
283 case SPECIAL_UNSIGNED_GTE:
284 if (strlen_left)
285 false_state = alloc_state_num(val);
286 else
287 true_state = alloc_state_num(val + 1);
288 break;
289 case '>':
290 case SPECIAL_UNSIGNED_GT:
291 if (strlen_left)
292 false_state = alloc_state_num(val + 1);
293 else
294 true_state = alloc_state_num(val);
295 break;
297 set_true_false_states_expr(my_size_id, str, true_state, false_state);
300 static struct expression *strip_ampersands(struct expression *expr)
302 struct symbol *type;
304 if (expr->type != EXPR_PREOP)
305 return expr;
306 if (expr->op != '&')
307 return expr;
308 type = get_type(expr->unop);
309 if (!type || type->type != SYM_ARRAY)
310 return expr;
311 return expr->unop;
314 static void match_array_assignment(struct expression *expr)
316 struct expression *left;
317 struct expression *right;
318 int array_size;
320 if (expr->op != '=')
321 return;
322 left = strip_expr(expr->left);
323 right = strip_expr(expr->right);
324 right = strip_ampersands(right);
325 array_size = get_array_size_bytes(right);
326 if (array_size)
327 set_state_expr(my_size_id, left, alloc_state_num(array_size));
330 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
332 int size_arg = (int)_size_arg;
333 struct expression *right;
334 struct expression *arg;
335 long long bytes;
337 right = strip_expr(expr->right);
338 arg = get_argument_from_call_expr(right->args, size_arg);
339 if (!get_implied_value(arg, &bytes))
340 return;
341 set_state_expr(my_size_id, expr->left, alloc_state_num(bytes));
344 static void match_calloc(const char *fn, struct expression *expr, void *unused)
346 struct expression *right;
347 struct expression *arg;
348 long long elements;
349 long long size;
351 right = strip_expr(expr->right);
352 arg = get_argument_from_call_expr(right->args, 0);
353 if (!get_implied_value(arg, &elements))
354 return;
355 arg = get_argument_from_call_expr(right->args, 1);
356 if (!get_implied_value(arg, &size))
357 return;
358 set_state_expr(my_size_id, expr->left, alloc_state_num(elements * size));
361 static void match_strlen(const char *fn, struct expression *expr, void *unused)
363 struct expression *right;
364 struct expression *str;
365 struct expression *len_expr;
366 char *len_name;
367 struct smatch_state *state;
369 right = strip_expr(expr->right);
370 str = get_argument_from_call_expr(right->args, 0);
371 len_expr = strip_expr(expr->left);
373 len_name = get_variable_from_expr(len_expr, NULL);
374 if (!len_name)
375 return;
377 state = __alloc_smatch_state(0);
378 state->name = len_name;
379 state->data = len_expr;
380 set_state_expr(my_strlen_id, str, state);
383 static void match_limited(const char *fn, struct expression *expr, void *_limiter)
385 struct limiter *limiter = (struct limiter *)_limiter;
386 struct expression *dest;
387 struct expression *size_expr;
388 long long size;
390 dest = get_argument_from_call_expr(expr->args, limiter->buf_arg);
391 size_expr = get_argument_from_call_expr(expr->args, limiter->limit_arg);
392 if (!get_implied_max(size_expr, &size))
393 return;
394 set_state_expr(my_size_id, dest, alloc_state_num(size));
397 static void match_strcpy(const char *fn, struct expression *expr, void *unused)
399 struct expression fake_assign;
401 fake_assign.op = '=';
402 fake_assign.left = get_argument_from_call_expr(expr->args, 0);
403 fake_assign.right = get_argument_from_call_expr(expr->args, 1);
404 match_array_assignment(&fake_assign);
407 static void match_strndup(const char *fn, struct expression *expr, void *unused)
409 struct expression *fn_expr;
410 struct expression *size_expr;
411 long long size;
413 fn_expr = strip_expr(expr->right);
414 size_expr = get_argument_from_call_expr(fn_expr->args, 1);
415 if (!get_implied_max(size_expr, &size))
416 return;
418 /* It's easy to forget space for the NUL char */
419 size++;
420 set_state_expr(my_size_id, expr->left, alloc_state_num(size));
423 static void match_call(struct expression *expr)
425 char *name;
426 struct expression *arg;
427 int bytes;
428 int i;
430 name = get_variable_from_expr(expr->fn, NULL);
431 if (!name)
432 return;
434 i = 0;
435 FOR_EACH_PTR(expr->args, arg) {
436 bytes = get_array_size_bytes(arg);
437 if (bytes > 1)
438 sm_msg("info: passes_buffer '%s' %d %d", name, i, bytes);
439 i++;
440 } END_FOR_EACH_PTR(arg);
442 free_string(name);
445 static void match_func_end(struct symbol *sym)
447 memset(params_set, 0, sizeof(params_set));
450 void register_buf_size(int id)
452 my_size_id = id;
454 add_hook(&match_function_def, FUNC_DEF_HOOK);
456 add_function_assign_hook("malloc", &match_alloc, INT_PTR(0));
457 add_function_assign_hook("calloc", &match_calloc, NULL);
458 add_function_assign_hook("memdup", &match_alloc, INT_PTR(1));
459 if (option_project == PROJ_KERNEL) {
460 add_function_assign_hook("kmalloc", &match_alloc, INT_PTR(0));
461 add_function_assign_hook("kzalloc", &match_alloc, INT_PTR(0));
462 add_function_assign_hook("vmalloc", &match_alloc, INT_PTR(0));
463 add_function_assign_hook("__vmalloc", &match_alloc, INT_PTR(0));
464 add_function_assign_hook("kcalloc", &match_calloc, NULL);
465 add_function_assign_hook("drm_malloc_ab", &match_calloc, NULL);
466 add_function_assign_hook("drm_calloc_large", &match_calloc, NULL);
467 add_function_assign_hook("kmemdup", &match_alloc, INT_PTR(1));
468 add_function_assign_hook("kmemdup_user", &match_alloc, INT_PTR(1));
470 add_hook(&match_array_assignment, ASSIGNMENT_HOOK);
471 add_hook(&match_strlen_condition, CONDITION_HOOK);
472 add_function_assign_hook("strlen", &match_strlen, NULL);
474 add_function_hook("strncpy", &match_limited, &b0_l2);
475 add_function_hook("strlcpy", &match_limited, &b0_l2);
476 add_function_hook("strlcat", &match_limited, &b0_l2);
477 add_function_hook("memcpy", &match_limited, &b0_l2);
478 add_function_hook("memscan", &match_limited, &b0_l2);
480 add_function_hook("strcpy", &match_strcpy, NULL);
482 add_function_assign_hook("strndup", match_strndup, NULL);
483 if (option_project == PROJ_KERNEL)
484 add_function_assign_hook("kstrndup", match_strndup, NULL);
486 if (option_info)
487 add_hook(&match_call, FUNCTION_CALL_HOOK);
489 add_hook(&match_func_end, END_FUNC_HOOK);
492 void register_strlen(int id)
494 my_strlen_id = id;