buf_size: record static variables in the database
[smatch.git] / smatch_buf_size.c
blob90d764d3dca76c0a86b5508f704c1d5d0f8c709a
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 if (db_size == 0)
128 db_size = atoi(argv[0]);
129 else
130 db_size = -1;
131 return 0;
134 static int size_from_db(struct expression *expr)
136 int this_file_only = 0;
137 char *name;
139 if (!option_spammy)
140 return 0;
142 name = get_member_name(expr);
143 if (!name && is_static(expr)) {
144 name = get_variable_from_expr(expr, NULL);
145 this_file_only = 1;
147 if (!name)
148 return 0;
150 db_size = 0;
151 run_sql(db_size_callback, "select size from type_size where type = '%s' and file = '%s'",
152 name, get_filename());
153 if (db_size == -1)
154 return 0;
155 if (db_size != 0)
156 return db_size;
157 if (this_file_only)
158 return 0;
160 run_sql(db_size_callback, "select size from type_size where type = '%s'",
161 name);
163 if (db_size == -1)
164 db_size = 0;
166 return db_size;
169 static int get_real_array_size(struct expression *expr)
171 struct symbol *type;
172 int ret;
174 if (expr->type == EXPR_BINOP) /* array elements foo[5] */
175 return 0;
177 type = get_type(expr);
178 if (!type || type->type != SYM_ARRAY)
179 return 0;
181 ret = get_expression_value(type->array_size);
182 /* Dynamically sized array are -1 in sparse */
183 if (ret <= 0)
184 return 0;
185 /* People put one element arrays on the end of structs */
186 if (ret == 1)
187 return 0;
189 return ret;
192 static int get_size_from_initializer(struct expression *expr)
194 if (expr->type != EXPR_SYMBOL || !expr->symbol->initializer)
195 return 0;
196 if (expr->symbol->initializer == expr) /* int a = a; */
197 return 0;
198 return get_initializer_size(expr->symbol->initializer);
201 static int get_stored_size_bytes(struct expression *expr)
203 struct smatch_state *state;
205 state = get_state_expr(my_size_id, expr);
206 if (!state)
207 return 0;
208 return PTR_INT(state->data);
211 static int get_bytes_from_address(struct expression *expr)
213 struct symbol *type;
214 int ret;
216 if (!option_spammy)
217 return 0;
218 if (expr->type != EXPR_PREOP || expr->op != '&')
219 return 0;
220 type = get_type(expr);
221 if (!type)
222 return 0;
224 if (type->type == SYM_PTR)
225 type = get_base_type(type);
227 ret = bits_to_bytes(type->bit_size);
228 if (ret == -1)
229 return 0;
230 if (ret == 1)
231 return 0; /* ignore char pointers */
233 return ret;
236 static int get_size_from_strlen(struct expression *expr)
238 struct smatch_state *state;
239 long long len;
241 state = get_state_expr(my_strlen_id, expr);
242 if (!state || !state->data)
243 return 0;
244 if (get_implied_max((struct expression *)state->data, &len))
245 return len + 1; /* add one because strlen doesn't include the NULL */
246 return 0;
249 static struct expression *remove_addr_fluff(struct expression *expr)
251 struct expression *tmp;
252 long long val;
254 expr = strip_expr(expr);
256 /* remove '&' and '*' operations that cancel */
257 while (expr->type == EXPR_PREOP && expr->op == '&') {
258 tmp = strip_expr(expr->unop);
259 if (tmp->type != EXPR_PREOP)
260 break;
261 if (tmp->op != '*')
262 break;
263 expr = strip_expr(tmp->unop);
266 /* "foo + 0" is just "foo" */
267 if (expr->type == EXPR_BINOP && expr->op == '+' &&
268 get_value(expr->right, &val) && val == 0)
269 return expr->left;
271 return expr;
274 int get_array_size_bytes(struct expression *expr)
276 int size;
278 expr = remove_addr_fluff(expr);
279 if (!expr)
280 return 0;
282 /* strcpy(foo, "BAR"); */
283 if (expr->type == EXPR_STRING)
284 return expr->string->length;
286 /* buf[4] */
287 size = get_real_array_size(expr);
288 if (size)
289 return elements_to_bytes(expr, size);
291 /* buf = malloc(1024); */
292 size = get_stored_size_bytes(expr);
293 if (size)
294 return size;
296 /* char *foo = "BAR" */
297 size = get_size_from_initializer(expr);
298 if (size)
299 return elements_to_bytes(expr, size);
301 size = get_bytes_from_address(expr);
302 if (size)
303 return size;
305 /* if (strlen(foo) > 4) */
306 size = get_size_from_strlen(expr);
307 if (size)
308 return size;
310 return size_from_db(expr);
313 int get_array_size(struct expression *expr)
315 int bytes;
317 bytes = get_array_size_bytes(expr);
318 return bytes_to_elements(expr, bytes);
321 static void match_strlen_condition(struct expression *expr)
323 struct expression *left;
324 struct expression *right;
325 struct expression *str = NULL;
326 int strlen_left = 0;
327 int strlen_right = 0;
328 long long val;
329 struct smatch_state *true_state = NULL;
330 struct smatch_state *false_state = NULL;
332 if (expr->type != EXPR_COMPARE)
333 return;
334 left = strip_expr(expr->left);
335 right = strip_expr(expr->right);
337 if (left->type == EXPR_CALL && sym_name_is("strlen", left->fn)) {
338 str = get_argument_from_call_expr(left->args, 0);
339 strlen_left = 1;
341 if (right->type == EXPR_CALL && sym_name_is("strlen", right->fn)) {
342 str = get_argument_from_call_expr(right->args, 0);
343 strlen_right = 1;
346 if (!strlen_left && !strlen_right)
347 return;
348 if (strlen_left && strlen_right)
349 return;
351 if (strlen_left) {
352 if (!get_value(right, &val))
353 return;
355 if (strlen_right) {
356 if (!get_value(left, &val))
357 return;
360 if (expr->op == SPECIAL_EQUAL) {
361 set_true_false_states_expr(my_size_id, str, alloc_state_num(val + 1), NULL);
362 return;
364 if (expr->op == SPECIAL_NOTEQUAL) {
365 set_true_false_states_expr(my_size_id, str, NULL, alloc_state_num(val + 1));
366 return;
369 switch (expr->op) {
370 case '<':
371 case SPECIAL_UNSIGNED_LT:
372 if (strlen_left)
373 true_state = alloc_state_num(val);
374 else
375 false_state = alloc_state_num(val + 1);
376 break;
377 case SPECIAL_LTE:
378 case SPECIAL_UNSIGNED_LTE:
379 if (strlen_left)
380 true_state = alloc_state_num(val + 1);
381 else
382 false_state = alloc_state_num(val);
383 break;
384 case SPECIAL_GTE:
385 case SPECIAL_UNSIGNED_GTE:
386 if (strlen_left)
387 false_state = alloc_state_num(val);
388 else
389 true_state = alloc_state_num(val + 1);
390 break;
391 case '>':
392 case SPECIAL_UNSIGNED_GT:
393 if (strlen_left)
394 false_state = alloc_state_num(val + 1);
395 else
396 true_state = alloc_state_num(val);
397 break;
399 set_true_false_states_expr(my_size_id, str, true_state, false_state);
402 static struct expression *strip_ampersands(struct expression *expr)
404 struct symbol *type;
406 if (expr->type != EXPR_PREOP)
407 return expr;
408 if (expr->op != '&')
409 return expr;
410 type = get_type(expr->unop);
411 if (!type || type->type != SYM_ARRAY)
412 return expr;
413 return expr->unop;
416 static void match_array_assignment(struct expression *expr)
418 struct expression *left;
419 struct expression *right;
420 int array_size;
422 if (expr->op != '=')
423 return;
424 left = strip_expr(expr->left);
425 right = strip_expr(expr->right);
426 right = strip_ampersands(right);
427 array_size = get_array_size_bytes(right);
428 if (array_size)
429 set_state_expr(my_size_id, left, alloc_state_num(array_size));
432 static void info_record_alloction(struct expression *buffer, struct expression *size)
434 char *name;
435 long long val;
437 if (!option_info)
438 return;
440 name = get_member_name(buffer);
441 if (!name && is_static(buffer))
442 name = get_variable_from_expr(buffer, NULL);
443 if (!name)
444 return;
445 if (!get_implied_value(size, &val))
446 val = -1;
447 sm_msg("info: '%s' allocated_buf_size %lld", name, val);
448 free_string(name);
451 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
453 int size_arg = PTR_INT(_size_arg);
454 struct expression *right;
455 struct expression *arg;
456 long long bytes;
458 right = strip_expr(expr->right);
459 arg = get_argument_from_call_expr(right->args, size_arg);
461 info_record_alloction(expr->left, arg);
463 if (!get_implied_value(arg, &bytes))
464 return;
465 set_state_expr(my_size_id, expr->left, alloc_state_num(bytes));
468 static void match_calloc(const char *fn, struct expression *expr, void *unused)
470 struct expression *right;
471 struct expression *arg;
472 long long elements;
473 long long size;
475 right = strip_expr(expr->right);
476 arg = get_argument_from_call_expr(right->args, 0);
477 if (!get_implied_value(arg, &elements))
478 return;
479 arg = get_argument_from_call_expr(right->args, 1);
480 if (!get_implied_value(arg, &size))
481 return;
482 set_state_expr(my_size_id, expr->left, alloc_state_num(elements * size));
485 static void match_strlen(const char *fn, struct expression *expr, void *unused)
487 struct expression *right;
488 struct expression *str;
489 struct expression *len_expr;
490 char *len_name;
491 struct smatch_state *state;
493 right = strip_expr(expr->right);
494 str = get_argument_from_call_expr(right->args, 0);
495 len_expr = strip_expr(expr->left);
497 len_name = get_variable_from_expr(len_expr, NULL);
498 if (!len_name)
499 return;
501 state = __alloc_smatch_state(0);
502 state->name = len_name;
503 state->data = len_expr;
504 set_state_expr(my_strlen_id, str, state);
507 static void match_limited(const char *fn, struct expression *expr, void *_limiter)
509 struct limiter *limiter = (struct limiter *)_limiter;
510 struct expression *dest;
511 struct expression *size_expr;
512 long long size;
514 dest = get_argument_from_call_expr(expr->args, limiter->buf_arg);
515 size_expr = get_argument_from_call_expr(expr->args, limiter->limit_arg);
516 if (!get_implied_max(size_expr, &size))
517 return;
518 set_state_expr(my_size_id, dest, alloc_state_num(size));
521 static void match_strcpy(const char *fn, struct expression *expr, void *unused)
523 struct expression fake_assign;
525 fake_assign.op = '=';
526 fake_assign.left = get_argument_from_call_expr(expr->args, 0);
527 fake_assign.right = get_argument_from_call_expr(expr->args, 1);
528 match_array_assignment(&fake_assign);
531 static void match_strndup(const char *fn, struct expression *expr, void *unused)
533 struct expression *fn_expr;
534 struct expression *size_expr;
535 long long size;
537 fn_expr = strip_expr(expr->right);
538 size_expr = get_argument_from_call_expr(fn_expr->args, 1);
539 if (!get_implied_max(size_expr, &size))
540 return;
542 /* It's easy to forget space for the NUL char */
543 size++;
544 set_state_expr(my_size_id, expr->left, alloc_state_num(size));
547 static void match_call(struct expression *expr)
549 char *name;
550 struct expression *arg;
551 int bytes;
552 int i;
554 name = get_fnptr_name(expr->fn);
555 if (!name)
556 return;
558 i = 0;
559 FOR_EACH_PTR(expr->args, arg) {
560 bytes = get_array_size_bytes(arg);
561 if (bytes > 1)
562 sm_msg("info: passes_buffer '%s' %d '$$' %d %s",
563 name, i, bytes,
564 is_static(expr->fn) ? "static" : "global");
565 i++;
566 } END_FOR_EACH_PTR(arg);
568 free_string(name);
571 static void struct_member_callback(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state)
573 if (state == &merged)
574 return;
575 sm_msg("info: passes_buffer '%s' %d '%s' %s %s", fn, param, printed_name, state->name, global_static);
578 static void match_func_end(struct symbol *sym)
580 memset(params_set, 0, sizeof(params_set));
583 void register_buf_size(int id)
585 my_size_id = id;
587 add_definition_db_callback(set_param_buf_size, BUF_SIZE);
589 add_function_assign_hook("malloc", &match_alloc, INT_PTR(0));
590 add_function_assign_hook("calloc", &match_calloc, NULL);
591 add_function_assign_hook("memdup", &match_alloc, INT_PTR(1));
592 if (option_project == PROJ_KERNEL) {
593 add_function_assign_hook("kmalloc", &match_alloc, INT_PTR(0));
594 add_function_assign_hook("kzalloc", &match_alloc, INT_PTR(0));
595 add_function_assign_hook("vmalloc", &match_alloc, INT_PTR(0));
596 add_function_assign_hook("__vmalloc", &match_alloc, INT_PTR(0));
597 add_function_assign_hook("kcalloc", &match_calloc, NULL);
598 add_function_assign_hook("kmalloc_array", &match_calloc, NULL);
599 add_function_assign_hook("drm_malloc_ab", &match_calloc, NULL);
600 add_function_assign_hook("drm_calloc_large", &match_calloc, NULL);
601 add_function_assign_hook("sock_kmalloc", &match_alloc, INT_PTR(1));
602 add_function_assign_hook("kmemdup", &match_alloc, INT_PTR(1));
603 add_function_assign_hook("kmemdup_user", &match_alloc, INT_PTR(1));
605 add_hook(&match_array_assignment, ASSIGNMENT_HOOK);
606 add_hook(&match_strlen_condition, CONDITION_HOOK);
607 add_function_assign_hook("strlen", &match_strlen, NULL);
609 add_function_assign_hook("strndup", match_strndup, NULL);
610 if (option_project == PROJ_KERNEL)
611 add_function_assign_hook("kstrndup", match_strndup, NULL);
613 add_hook(&match_func_end, END_FUNC_HOOK);
614 add_modification_hook(my_size_id, &set_undefined);
617 void register_strlen(int id)
619 my_strlen_id = id;
620 add_modification_hook(my_strlen_id, &set_undefined);
623 void register_buf_size_late(int id)
625 add_function_hook("strlcpy", &match_limited, &b0_l2);
626 add_function_hook("strlcat", &match_limited, &b0_l2);
627 add_function_hook("memscan", &match_limited, &b0_l2);
629 add_function_hook("strcpy", &match_strcpy, NULL);
631 if (option_info) {
632 add_hook(&match_call, FUNCTION_CALL_HOOK);
633 add_member_info_callback(my_size_id, struct_member_callback);