deref_check: silence some false positive on cross function derefs
[smatch.git] / smatch_buf_size.c
blobe6c5e580d588d217f6d6f517f24b09c425eb0fce
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 if (expr->type == EXPR_BINOP) /* array elements foo[5] */
154 return 0;
156 type = get_type(expr);
157 if (!type || type->type != SYM_ARRAY)
158 return 0;
160 ret = get_expression_value(type->array_size);
161 /* Dynamically sized array are -1 in sparse */
162 if (ret <= 0)
163 return 0;
164 /* People put one element arrays on the end of structs */
165 if (ret == 1)
166 return 0;
168 return ret;
171 static int get_size_from_initializer(struct expression *expr)
173 if (expr->type != EXPR_SYMBOL || !expr->symbol->initializer)
174 return 0;
175 if (expr->symbol->initializer == expr) /* int a = a; */
176 return 0;
177 return get_initializer_size(expr->symbol->initializer);
180 static int get_stored_size_bytes(struct expression *expr)
182 struct smatch_state *state;
184 state = get_state_expr(my_size_id, expr);
185 if (!state)
186 return 0;
187 return PTR_INT(state->data);
190 static int get_bytes_from_address(struct expression *expr)
192 struct symbol *type;
193 int ret;
195 if (!option_spammy)
196 return 0;
197 if (expr->type != EXPR_PREOP || expr->op != '&')
198 return 0;
199 type = get_type(expr);
200 if (!type)
201 return 0;
203 if (type->type == SYM_PTR)
204 type = get_base_type(type);
206 ret = bits_to_bytes(type->bit_size);
207 if (ret == -1)
208 return 0;
209 if (ret == 1)
210 return 0; /* ignore char pointers */
212 return ret;
215 static int get_size_from_strlen(struct expression *expr)
217 struct smatch_state *state;
218 long long len;
220 state = get_state_expr(my_strlen_id, expr);
221 if (!state || !state->data)
222 return 0;
223 if (get_implied_max((struct expression *)state->data, &len))
224 return len + 1; /* add one because strlen doesn't include the NULL */
225 return 0;
228 static struct expression *remove_addr_fluff(struct expression *expr)
230 struct expression *tmp;
231 long long val;
233 expr = strip_expr(expr);
235 /* remove '&' and '*' operations that cancel */
236 while (expr->type == EXPR_PREOP && expr->op == '&') {
237 tmp = strip_expr(expr->unop);
238 if (tmp->type != EXPR_PREOP)
239 break;
240 if (tmp->op != '*')
241 break;
242 expr = strip_expr(tmp->unop);
245 /* "foo + 0" is just "foo" */
246 if (expr->type == EXPR_BINOP && expr->op == '+' &&
247 get_value(expr->right, &val) && val == 0)
248 return expr->left;
250 return expr;
253 int get_array_size_bytes(struct expression *expr)
255 int size;
257 expr = remove_addr_fluff(expr);
258 if (!expr)
259 return 0;
261 /* strcpy(foo, "BAR"); */
262 if (expr->type == EXPR_STRING)
263 return expr->string->length;
265 /* buf[4] */
266 size = get_real_array_size(expr);
267 if (size)
268 return elements_to_bytes(expr, size);
270 /* buf = malloc(1024); */
271 size = get_stored_size_bytes(expr);
272 if (size)
273 return size;
275 /* char *foo = "BAR" */
276 size = get_size_from_initializer(expr);
277 if (size)
278 return elements_to_bytes(expr, size);
280 size = get_bytes_from_address(expr);
281 if (size)
282 return size;
284 /* if (strlen(foo) > 4) */
285 size = get_size_from_strlen(expr);
286 if (size)
287 return size;
289 return size_from_db(expr);
292 int get_array_size(struct expression *expr)
294 int bytes;
296 bytes = get_array_size_bytes(expr);
297 return bytes_to_elements(expr, bytes);
300 static void match_strlen_condition(struct expression *expr)
302 struct expression *left;
303 struct expression *right;
304 struct expression *str = NULL;
305 int strlen_left = 0;
306 int strlen_right = 0;
307 long long val;
308 struct smatch_state *true_state = NULL;
309 struct smatch_state *false_state = NULL;
311 if (expr->type != EXPR_COMPARE)
312 return;
313 left = strip_expr(expr->left);
314 right = strip_expr(expr->right);
316 if (left->type == EXPR_CALL && sym_name_is("strlen", left->fn)) {
317 str = get_argument_from_call_expr(left->args, 0);
318 strlen_left = 1;
320 if (right->type == EXPR_CALL && sym_name_is("strlen", right->fn)) {
321 str = get_argument_from_call_expr(right->args, 0);
322 strlen_right = 1;
325 if (!strlen_left && !strlen_right)
326 return;
327 if (strlen_left && strlen_right)
328 return;
330 if (strlen_left) {
331 if (!get_value(right, &val))
332 return;
334 if (strlen_right) {
335 if (!get_value(left, &val))
336 return;
339 if (expr->op == SPECIAL_EQUAL) {
340 set_true_false_states_expr(my_size_id, str, alloc_state_num(val + 1), NULL);
341 return;
343 if (expr->op == SPECIAL_NOTEQUAL) {
344 set_true_false_states_expr(my_size_id, str, NULL, alloc_state_num(val + 1));
345 return;
348 switch (expr->op) {
349 case '<':
350 case SPECIAL_UNSIGNED_LT:
351 if (strlen_left)
352 true_state = alloc_state_num(val);
353 else
354 false_state = alloc_state_num(val + 1);
355 break;
356 case SPECIAL_LTE:
357 case SPECIAL_UNSIGNED_LTE:
358 if (strlen_left)
359 true_state = alloc_state_num(val + 1);
360 else
361 false_state = alloc_state_num(val);
362 break;
363 case SPECIAL_GTE:
364 case SPECIAL_UNSIGNED_GTE:
365 if (strlen_left)
366 false_state = alloc_state_num(val);
367 else
368 true_state = alloc_state_num(val + 1);
369 break;
370 case '>':
371 case SPECIAL_UNSIGNED_GT:
372 if (strlen_left)
373 false_state = alloc_state_num(val + 1);
374 else
375 true_state = alloc_state_num(val);
376 break;
378 set_true_false_states_expr(my_size_id, str, true_state, false_state);
381 static struct expression *strip_ampersands(struct expression *expr)
383 struct symbol *type;
385 if (expr->type != EXPR_PREOP)
386 return expr;
387 if (expr->op != '&')
388 return expr;
389 type = get_type(expr->unop);
390 if (!type || type->type != SYM_ARRAY)
391 return expr;
392 return expr->unop;
395 static void match_array_assignment(struct expression *expr)
397 struct expression *left;
398 struct expression *right;
399 int array_size;
401 if (expr->op != '=')
402 return;
403 left = strip_expr(expr->left);
404 right = strip_expr(expr->right);
405 right = strip_ampersands(right);
406 array_size = get_array_size_bytes(right);
407 if (array_size)
408 set_state_expr(my_size_id, left, alloc_state_num(array_size));
411 static void info_record_alloction(struct expression *buffer, struct expression *size)
413 char *member;
414 long long val;
416 if (!option_info)
417 return;
418 member = get_member_name(buffer);
419 if (!member)
420 return;
421 if (!get_implied_value(size, &val))
422 val = -1;
423 sm_msg("info: '%s' allocated_buf_size %lld", member, val);
424 free_string(member);
427 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
429 int size_arg = PTR_INT(_size_arg);
430 struct expression *right;
431 struct expression *arg;
432 long long bytes;
434 right = strip_expr(expr->right);
435 arg = get_argument_from_call_expr(right->args, size_arg);
437 info_record_alloction(expr->left, arg);
439 if (!get_implied_value(arg, &bytes))
440 return;
441 set_state_expr(my_size_id, expr->left, alloc_state_num(bytes));
444 static void match_calloc(const char *fn, struct expression *expr, void *unused)
446 struct expression *right;
447 struct expression *arg;
448 long long elements;
449 long long size;
451 right = strip_expr(expr->right);
452 arg = get_argument_from_call_expr(right->args, 0);
453 if (!get_implied_value(arg, &elements))
454 return;
455 arg = get_argument_from_call_expr(right->args, 1);
456 if (!get_implied_value(arg, &size))
457 return;
458 set_state_expr(my_size_id, expr->left, alloc_state_num(elements * size));
461 static void match_strlen(const char *fn, struct expression *expr, void *unused)
463 struct expression *right;
464 struct expression *str;
465 struct expression *len_expr;
466 char *len_name;
467 struct smatch_state *state;
469 right = strip_expr(expr->right);
470 str = get_argument_from_call_expr(right->args, 0);
471 len_expr = strip_expr(expr->left);
473 len_name = get_variable_from_expr(len_expr, NULL);
474 if (!len_name)
475 return;
477 state = __alloc_smatch_state(0);
478 state->name = len_name;
479 state->data = len_expr;
480 set_state_expr(my_strlen_id, str, state);
483 static void match_limited(const char *fn, struct expression *expr, void *_limiter)
485 struct limiter *limiter = (struct limiter *)_limiter;
486 struct expression *dest;
487 struct expression *size_expr;
488 long long size;
490 dest = get_argument_from_call_expr(expr->args, limiter->buf_arg);
491 size_expr = get_argument_from_call_expr(expr->args, limiter->limit_arg);
492 if (!get_implied_max(size_expr, &size))
493 return;
494 set_state_expr(my_size_id, dest, alloc_state_num(size));
497 static void match_strcpy(const char *fn, struct expression *expr, void *unused)
499 struct expression fake_assign;
501 fake_assign.op = '=';
502 fake_assign.left = get_argument_from_call_expr(expr->args, 0);
503 fake_assign.right = get_argument_from_call_expr(expr->args, 1);
504 match_array_assignment(&fake_assign);
507 static void match_strndup(const char *fn, struct expression *expr, void *unused)
509 struct expression *fn_expr;
510 struct expression *size_expr;
511 long long size;
513 fn_expr = strip_expr(expr->right);
514 size_expr = get_argument_from_call_expr(fn_expr->args, 1);
515 if (!get_implied_max(size_expr, &size))
516 return;
518 /* It's easy to forget space for the NUL char */
519 size++;
520 set_state_expr(my_size_id, expr->left, alloc_state_num(size));
523 static void match_call(struct expression *expr)
525 char *name;
526 struct expression *arg;
527 int bytes;
528 int i;
530 name = get_fnptr_name(expr->fn);
531 if (!name)
532 return;
534 i = 0;
535 FOR_EACH_PTR(expr->args, arg) {
536 bytes = get_array_size_bytes(arg);
537 if (bytes > 1)
538 sm_msg("info: passes_buffer '%s' %d '$$' %d %s",
539 name, i, bytes,
540 is_static(expr->fn) ? "static" : "global");
541 i++;
542 } END_FOR_EACH_PTR(arg);
544 free_string(name);
547 static void struct_member_callback(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state)
549 if (state == &merged)
550 return;
551 sm_msg("info: passes_buffer '%s' %d '%s' %s %s", fn, param, printed_name, state->name, global_static);
554 static void match_func_end(struct symbol *sym)
556 memset(params_set, 0, sizeof(params_set));
559 void register_buf_size(int id)
561 my_size_id = id;
563 add_definition_db_callback(set_param_buf_size, BUF_SIZE);
565 add_function_assign_hook("malloc", &match_alloc, INT_PTR(0));
566 add_function_assign_hook("calloc", &match_calloc, NULL);
567 add_function_assign_hook("memdup", &match_alloc, INT_PTR(1));
568 if (option_project == PROJ_KERNEL) {
569 add_function_assign_hook("kmalloc", &match_alloc, INT_PTR(0));
570 add_function_assign_hook("kzalloc", &match_alloc, INT_PTR(0));
571 add_function_assign_hook("vmalloc", &match_alloc, INT_PTR(0));
572 add_function_assign_hook("__vmalloc", &match_alloc, INT_PTR(0));
573 add_function_assign_hook("kcalloc", &match_calloc, NULL);
574 add_function_assign_hook("kmalloc_array", &match_calloc, NULL);
575 add_function_assign_hook("drm_malloc_ab", &match_calloc, NULL);
576 add_function_assign_hook("drm_calloc_large", &match_calloc, NULL);
577 add_function_assign_hook("sock_kmalloc", &match_alloc, INT_PTR(1));
578 add_function_assign_hook("kmemdup", &match_alloc, INT_PTR(1));
579 add_function_assign_hook("kmemdup_user", &match_alloc, INT_PTR(1));
581 add_hook(&match_array_assignment, ASSIGNMENT_HOOK);
582 add_hook(&match_strlen_condition, CONDITION_HOOK);
583 add_function_assign_hook("strlen", &match_strlen, NULL);
585 add_function_assign_hook("strndup", match_strndup, NULL);
586 if (option_project == PROJ_KERNEL)
587 add_function_assign_hook("kstrndup", match_strndup, NULL);
589 add_hook(&match_func_end, END_FUNC_HOOK);
590 add_modification_hook(my_size_id, &set_undefined);
593 void register_strlen(int id)
595 my_strlen_id = id;
596 add_modification_hook(my_strlen_id, &set_undefined);
599 void register_buf_size_late(int id)
601 add_function_hook("strlcpy", &match_limited, &b0_l2);
602 add_function_hook("strlcat", &match_limited, &b0_l2);
603 add_function_hook("memscan", &match_limited, &b0_l2);
605 add_function_hook("strcpy", &match_strcpy, NULL);
607 if (option_info) {
608 add_hook(&match_call, FUNCTION_CALL_HOOK);
609 add_member_info_callback(my_size_id, struct_member_callback);