buf_size: remove cast_ratio()
[smatch.git] / smatch_buf_size.c
blob02ee4f2ea85f19e7d44e7cc3dd3a65a8fd69f947
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 void set_undefined(struct sm_state *sm)
36 if (sm->state != &undefined)
37 set_state(sm->owner, sm->name, sm->sym, &undefined);
40 void set_param_buf_size(const char *name, struct symbol *sym, char *key, char *value)
42 char fullname[256];
43 unsigned int size;
45 if (strncmp(key, "$$", 2))
46 return;
48 snprintf(fullname, 256, "%s%s", name, key + 2);
50 errno = 0;
51 size = strtoul(value, NULL, 10);
52 if (errno)
53 return;
55 set_state(my_size_id, fullname, sym, alloc_state_num(size));
58 static int bytes_per_element(struct expression *expr)
60 struct symbol *type;
61 int bpe;
63 if (expr->type == EXPR_STRING)
64 return 1;
65 type = get_type(expr);
66 if (!type)
67 return 0;
69 if (type->type != SYM_PTR && type->type != SYM_ARRAY)
70 return 0;
72 type = get_base_type(type);
73 bpe = bits_to_bytes(type->bit_size);
75 if (bpe == -1) /* void pointer */
76 bpe = 1;
78 return bpe;
81 static int bytes_to_elements(struct expression *expr, int bytes)
83 int bpe;
85 bpe = bytes_per_element(expr);
86 if (bpe == 0)
87 return 0;
88 return bytes / bpe;
91 static int elements_to_bytes(struct expression *expr, int elements)
93 int bpe;
95 bpe = bytes_per_element(expr);
96 return elements * bpe;
99 static int get_initializer_size(struct expression *expr)
101 switch (expr->type) {
102 case EXPR_STRING:
103 return expr->string->length;
104 case EXPR_INITIALIZER: {
105 struct expression *tmp;
106 int i = 0;
107 int max = 0;
109 FOR_EACH_PTR(expr->expr_list, tmp) {
110 if (tmp->type == EXPR_INDEX && tmp->idx_to > max)
111 max = tmp->idx_to;
112 i++;
113 } END_FOR_EACH_PTR(tmp);
114 if (max)
115 return max + 1;
116 return i;
118 case EXPR_SYMBOL:
119 return get_array_size(expr);
121 return 0;
124 static int db_size;
125 static int db_size_callback(void *unused, int argc, char **argv, char **azColName)
127 db_size = atoi(argv[0]);
128 return 0;
131 static int size_from_db(struct expression *expr)
133 char *name;
135 if (!option_spammy)
136 return 0;
138 name = get_member_name(expr);
139 if (!name)
140 return 0;
142 db_size = 0;
143 run_sql(db_size_callback, "select size from type_size where type = '%s'",
144 name);
145 return db_size;
148 static int get_real_array_size(struct expression *expr)
150 struct symbol *type;
151 int ret;
153 type = get_type(expr);
154 if (!type || type->type != SYM_ARRAY)
155 return 0;
157 ret = get_expression_value(type->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;
165 return ret;
168 static int get_size_from_initializer(struct expression *expr)
170 if (expr->type != EXPR_SYMBOL || !expr->symbol->initializer)
171 return 0;
172 if (expr->symbol->initializer == expr) /* int a = a; */
173 return 0;
174 return get_initializer_size(expr->symbol->initializer);
177 static int get_stored_size_bytes(struct expression *expr)
179 struct sm_state *sm, *tmp;
180 int max = 0;
182 sm = get_sm_state_expr(my_size_id, expr);
183 if (!sm)
184 return 0;
186 FOR_EACH_PTR(sm->possible, tmp) {
187 if (PTR_INT(tmp->state->data) > max)
188 max = PTR_INT(tmp->state->data);
189 } END_FOR_EACH_PTR(tmp);
191 return max;
194 static int get_stored_size(struct expression *expr)
196 int size;
198 size = get_stored_size_bytes(expr);
199 size = bytes_to_elements(expr, size);
200 return size;
203 static int get_size_from_strlen(struct expression *expr)
205 struct smatch_state *state;
206 long long len;
208 state = get_state_expr(my_strlen_id, expr);
209 if (!state || !state->data)
210 return 0;
211 if (get_implied_max((struct expression *)state->data, &len))
212 return len + 1; /* add one because strlen doesn't include the NULL */
213 return 0;
216 int get_array_size(struct expression *expr)
218 int ret;
220 expr = strip_expr(expr);
221 if (!expr)
222 return 0;
224 /* strcpy(foo, "BAR"); */
225 if (expr->type == EXPR_STRING)
226 return expr->string->length;
228 /* buf[4] */
229 ret = get_real_array_size(expr);
230 if (ret)
231 return ret;
233 /* buf = malloc(1024); */
234 ret = get_stored_size(expr);
235 if (ret)
236 return ret;
238 /* char *foo = "BAR" */
239 ret = get_size_from_initializer(expr);
240 if (ret)
241 return ret;
243 /* if (strlen(foo) > 4) */
244 ret = get_size_from_strlen(expr);
245 if (ret)
246 return ret;
247 return 0;
250 int get_array_size_bytes(struct expression *expr)
252 int size;
254 expr = strip_expr(expr);
255 if (!expr)
256 return 0;
258 size = get_real_array_size(expr);
259 if (size)
260 return elements_to_bytes(expr, size);
262 size = get_stored_size_bytes(expr);
263 if (size)
264 return size;
266 size = get_array_size(expr);
267 if (size)
268 return elements_to_bytes(expr, size);
270 return size_from_db(expr);
273 static void match_strlen_condition(struct expression *expr)
275 struct expression *left;
276 struct expression *right;
277 struct expression *str = NULL;
278 int strlen_left = 0;
279 int strlen_right = 0;
280 long long val;
281 struct smatch_state *true_state = NULL;
282 struct smatch_state *false_state = NULL;
284 if (expr->type != EXPR_COMPARE)
285 return;
286 left = strip_expr(expr->left);
287 right = strip_expr(expr->right);
289 if (left->type == EXPR_CALL && sym_name_is("strlen", left->fn)) {
290 str = get_argument_from_call_expr(left->args, 0);
291 strlen_left = 1;
293 if (right->type == EXPR_CALL && sym_name_is("strlen", right->fn)) {
294 str = get_argument_from_call_expr(right->args, 0);
295 strlen_right = 1;
298 if (!strlen_left && !strlen_right)
299 return;
300 if (strlen_left && strlen_right)
301 return;
303 if (strlen_left) {
304 if (!get_value(right, &val))
305 return;
307 if (strlen_right) {
308 if (!get_value(left, &val))
309 return;
312 if (expr->op == SPECIAL_EQUAL) {
313 set_true_false_states_expr(my_size_id, str, alloc_state_num(val + 1), NULL);
314 return;
316 if (expr->op == SPECIAL_NOTEQUAL) {
317 set_true_false_states_expr(my_size_id, str, NULL, alloc_state_num(val + 1));
318 return;
321 switch (expr->op) {
322 case '<':
323 case SPECIAL_UNSIGNED_LT:
324 if (strlen_left)
325 true_state = alloc_state_num(val);
326 else
327 false_state = alloc_state_num(val + 1);
328 break;
329 case SPECIAL_LTE:
330 case SPECIAL_UNSIGNED_LTE:
331 if (strlen_left)
332 true_state = alloc_state_num(val + 1);
333 else
334 false_state = alloc_state_num(val);
335 break;
336 case SPECIAL_GTE:
337 case SPECIAL_UNSIGNED_GTE:
338 if (strlen_left)
339 false_state = alloc_state_num(val);
340 else
341 true_state = alloc_state_num(val + 1);
342 break;
343 case '>':
344 case SPECIAL_UNSIGNED_GT:
345 if (strlen_left)
346 false_state = alloc_state_num(val + 1);
347 else
348 true_state = alloc_state_num(val);
349 break;
351 set_true_false_states_expr(my_size_id, str, true_state, false_state);
354 static struct expression *strip_ampersands(struct expression *expr)
356 struct symbol *type;
358 if (expr->type != EXPR_PREOP)
359 return expr;
360 if (expr->op != '&')
361 return expr;
362 type = get_type(expr->unop);
363 if (!type || type->type != SYM_ARRAY)
364 return expr;
365 return expr->unop;
368 static void match_array_assignment(struct expression *expr)
370 struct expression *left;
371 struct expression *right;
372 int array_size;
374 if (expr->op != '=')
375 return;
376 left = strip_expr(expr->left);
377 right = strip_expr(expr->right);
378 right = strip_ampersands(right);
379 array_size = get_array_size_bytes(right);
380 if (array_size)
381 set_state_expr(my_size_id, left, alloc_state_num(array_size));
384 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
386 int size_arg = PTR_INT(_size_arg);
387 struct expression *right;
388 struct expression *arg;
389 long long bytes;
391 right = strip_expr(expr->right);
392 arg = get_argument_from_call_expr(right->args, size_arg);
393 if (!get_implied_value(arg, &bytes))
394 return;
396 set_state_expr(my_size_id, expr->left, alloc_state_num(bytes));
398 if (option_info) {
399 char *member = get_member_name(expr->left);
401 if (member)
402 sm_msg("info: '%s' allocated_buf_size %lld",
403 member, bytes);
404 free_string(member);
408 static void match_calloc(const char *fn, struct expression *expr, void *unused)
410 struct expression *right;
411 struct expression *arg;
412 long long elements;
413 long long size;
415 right = strip_expr(expr->right);
416 arg = get_argument_from_call_expr(right->args, 0);
417 if (!get_implied_value(arg, &elements))
418 return;
419 arg = get_argument_from_call_expr(right->args, 1);
420 if (!get_implied_value(arg, &size))
421 return;
422 set_state_expr(my_size_id, expr->left, alloc_state_num(elements * size));
425 static void match_strlen(const char *fn, struct expression *expr, void *unused)
427 struct expression *right;
428 struct expression *str;
429 struct expression *len_expr;
430 char *len_name;
431 struct smatch_state *state;
433 right = strip_expr(expr->right);
434 str = get_argument_from_call_expr(right->args, 0);
435 len_expr = strip_expr(expr->left);
437 len_name = get_variable_from_expr(len_expr, NULL);
438 if (!len_name)
439 return;
441 state = __alloc_smatch_state(0);
442 state->name = len_name;
443 state->data = len_expr;
444 set_state_expr(my_strlen_id, str, state);
447 static void match_limited(const char *fn, struct expression *expr, void *_limiter)
449 struct limiter *limiter = (struct limiter *)_limiter;
450 struct expression *dest;
451 struct expression *size_expr;
452 long long size;
454 dest = get_argument_from_call_expr(expr->args, limiter->buf_arg);
455 size_expr = get_argument_from_call_expr(expr->args, limiter->limit_arg);
456 if (!get_implied_max(size_expr, &size))
457 return;
458 set_state_expr(my_size_id, dest, alloc_state_num(size));
461 static void match_strcpy(const char *fn, struct expression *expr, void *unused)
463 struct expression fake_assign;
465 fake_assign.op = '=';
466 fake_assign.left = get_argument_from_call_expr(expr->args, 0);
467 fake_assign.right = get_argument_from_call_expr(expr->args, 1);
468 match_array_assignment(&fake_assign);
471 static void match_strndup(const char *fn, struct expression *expr, void *unused)
473 struct expression *fn_expr;
474 struct expression *size_expr;
475 long long size;
477 fn_expr = strip_expr(expr->right);
478 size_expr = get_argument_from_call_expr(fn_expr->args, 1);
479 if (!get_implied_max(size_expr, &size))
480 return;
482 /* It's easy to forget space for the NUL char */
483 size++;
484 set_state_expr(my_size_id, expr->left, alloc_state_num(size));
487 static void match_call(struct expression *expr)
489 char *name;
490 struct expression *arg;
491 int bytes;
492 int i;
494 name = get_fnptr_name(expr->fn);
495 if (!name)
496 return;
498 i = 0;
499 FOR_EACH_PTR(expr->args, arg) {
500 bytes = get_array_size_bytes(arg);
501 if (bytes > 1)
502 sm_msg("info: passes_buffer '%s' %d '$$' %d %s",
503 name, i, bytes,
504 is_static(expr->fn) ? "static" : "global");
505 i++;
506 } END_FOR_EACH_PTR(arg);
508 free_string(name);
511 static void struct_member_callback(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state)
513 if (state == &merged)
514 return;
515 sm_msg("info: passes_buffer '%s' %d '%s' %s %s", fn, param, printed_name, state->name, global_static);
518 static void match_func_end(struct symbol *sym)
520 memset(params_set, 0, sizeof(params_set));
523 void register_buf_size(int id)
525 my_size_id = id;
527 add_definition_db_callback(set_param_buf_size, BUF_SIZE);
529 add_function_assign_hook("malloc", &match_alloc, INT_PTR(0));
530 add_function_assign_hook("calloc", &match_calloc, NULL);
531 add_function_assign_hook("memdup", &match_alloc, INT_PTR(1));
532 if (option_project == PROJ_KERNEL) {
533 add_function_assign_hook("kmalloc", &match_alloc, INT_PTR(0));
534 add_function_assign_hook("kzalloc", &match_alloc, INT_PTR(0));
535 add_function_assign_hook("vmalloc", &match_alloc, INT_PTR(0));
536 add_function_assign_hook("__vmalloc", &match_alloc, INT_PTR(0));
537 add_function_assign_hook("kcalloc", &match_calloc, NULL);
538 add_function_assign_hook("drm_malloc_ab", &match_calloc, NULL);
539 add_function_assign_hook("drm_calloc_large", &match_calloc, NULL);
540 add_function_assign_hook("kmemdup", &match_alloc, INT_PTR(1));
541 add_function_assign_hook("kmemdup_user", &match_alloc, INT_PTR(1));
543 add_hook(&match_array_assignment, ASSIGNMENT_HOOK);
544 add_hook(&match_strlen_condition, CONDITION_HOOK);
545 add_function_assign_hook("strlen", &match_strlen, NULL);
547 add_function_assign_hook("strndup", match_strndup, NULL);
548 if (option_project == PROJ_KERNEL)
549 add_function_assign_hook("kstrndup", match_strndup, NULL);
551 add_hook(&match_func_end, END_FUNC_HOOK);
552 add_modification_hook(my_size_id, &set_undefined);
555 void register_strlen(int id)
557 my_strlen_id = id;
558 add_modification_hook(my_strlen_id, &set_undefined);
561 void register_buf_size_late(int id)
563 add_function_hook("strlcpy", &match_limited, &b0_l2);
564 add_function_hook("strlcat", &match_limited, &b0_l2);
565 add_function_hook("memscan", &match_limited, &b0_l2);
567 add_function_hook("strcpy", &match_strcpy, NULL);
569 if (option_info) {
570 add_hook(&match_call, FUNCTION_CALL_HOOK);
571 add_member_info_callback(my_size_id, struct_member_callback);