proc_create: fix a whitespace issue
[smatch.git] / smatch_buf_size.c
blob48fe19ef48da96b6e8258acce381ad007b01465b
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 char *name;
138 if (!option_spammy)
139 return 0;
141 name = get_member_name(expr);
142 if (!name)
143 return 0;
145 db_size = 0;
146 run_sql(db_size_callback, "select size from type_size where type = '%s' and file = '%s'",
147 name, get_filename());
148 if (db_size == -1)
149 return 0;
150 if (db_size != 0)
151 return db_size;
153 run_sql(db_size_callback, "select size from type_size where type = '%s'",
154 name);
156 if (db_size == -1)
157 db_size = 0;
159 return db_size;
162 static int get_real_array_size(struct expression *expr)
164 struct symbol *type;
165 int ret;
167 if (expr->type == EXPR_BINOP) /* array elements foo[5] */
168 return 0;
170 type = get_type(expr);
171 if (!type || type->type != SYM_ARRAY)
172 return 0;
174 ret = get_expression_value(type->array_size);
175 /* Dynamically sized array are -1 in sparse */
176 if (ret <= 0)
177 return 0;
178 /* People put one element arrays on the end of structs */
179 if (ret == 1)
180 return 0;
182 return ret;
185 static int get_size_from_initializer(struct expression *expr)
187 if (expr->type != EXPR_SYMBOL || !expr->symbol->initializer)
188 return 0;
189 if (expr->symbol->initializer == expr) /* int a = a; */
190 return 0;
191 return get_initializer_size(expr->symbol->initializer);
194 static int get_stored_size_bytes(struct expression *expr)
196 struct smatch_state *state;
198 state = get_state_expr(my_size_id, expr);
199 if (!state)
200 return 0;
201 return PTR_INT(state->data);
204 static int get_bytes_from_address(struct expression *expr)
206 struct symbol *type;
207 int ret;
209 if (!option_spammy)
210 return 0;
211 if (expr->type != EXPR_PREOP || expr->op != '&')
212 return 0;
213 type = get_type(expr);
214 if (!type)
215 return 0;
217 if (type->type == SYM_PTR)
218 type = get_base_type(type);
220 ret = bits_to_bytes(type->bit_size);
221 if (ret == -1)
222 return 0;
223 if (ret == 1)
224 return 0; /* ignore char pointers */
226 return ret;
229 static int get_size_from_strlen(struct expression *expr)
231 struct smatch_state *state;
232 long long len;
234 state = get_state_expr(my_strlen_id, expr);
235 if (!state || !state->data)
236 return 0;
237 if (get_implied_max((struct expression *)state->data, &len))
238 return len + 1; /* add one because strlen doesn't include the NULL */
239 return 0;
242 static struct expression *remove_addr_fluff(struct expression *expr)
244 struct expression *tmp;
245 long long val;
247 expr = strip_expr(expr);
249 /* remove '&' and '*' operations that cancel */
250 while (expr->type == EXPR_PREOP && expr->op == '&') {
251 tmp = strip_expr(expr->unop);
252 if (tmp->type != EXPR_PREOP)
253 break;
254 if (tmp->op != '*')
255 break;
256 expr = strip_expr(tmp->unop);
259 /* "foo + 0" is just "foo" */
260 if (expr->type == EXPR_BINOP && expr->op == '+' &&
261 get_value(expr->right, &val) && val == 0)
262 return expr->left;
264 return expr;
267 int get_array_size_bytes(struct expression *expr)
269 int size;
271 expr = remove_addr_fluff(expr);
272 if (!expr)
273 return 0;
275 /* strcpy(foo, "BAR"); */
276 if (expr->type == EXPR_STRING)
277 return expr->string->length;
279 /* buf[4] */
280 size = get_real_array_size(expr);
281 if (size)
282 return elements_to_bytes(expr, size);
284 /* buf = malloc(1024); */
285 size = get_stored_size_bytes(expr);
286 if (size)
287 return size;
289 /* char *foo = "BAR" */
290 size = get_size_from_initializer(expr);
291 if (size)
292 return elements_to_bytes(expr, size);
294 size = get_bytes_from_address(expr);
295 if (size)
296 return size;
298 /* if (strlen(foo) > 4) */
299 size = get_size_from_strlen(expr);
300 if (size)
301 return size;
303 return size_from_db(expr);
306 int get_array_size(struct expression *expr)
308 int bytes;
310 bytes = get_array_size_bytes(expr);
311 return bytes_to_elements(expr, bytes);
314 static void match_strlen_condition(struct expression *expr)
316 struct expression *left;
317 struct expression *right;
318 struct expression *str = NULL;
319 int strlen_left = 0;
320 int strlen_right = 0;
321 long long val;
322 struct smatch_state *true_state = NULL;
323 struct smatch_state *false_state = NULL;
325 if (expr->type != EXPR_COMPARE)
326 return;
327 left = strip_expr(expr->left);
328 right = strip_expr(expr->right);
330 if (left->type == EXPR_CALL && sym_name_is("strlen", left->fn)) {
331 str = get_argument_from_call_expr(left->args, 0);
332 strlen_left = 1;
334 if (right->type == EXPR_CALL && sym_name_is("strlen", right->fn)) {
335 str = get_argument_from_call_expr(right->args, 0);
336 strlen_right = 1;
339 if (!strlen_left && !strlen_right)
340 return;
341 if (strlen_left && strlen_right)
342 return;
344 if (strlen_left) {
345 if (!get_value(right, &val))
346 return;
348 if (strlen_right) {
349 if (!get_value(left, &val))
350 return;
353 if (expr->op == SPECIAL_EQUAL) {
354 set_true_false_states_expr(my_size_id, str, alloc_state_num(val + 1), NULL);
355 return;
357 if (expr->op == SPECIAL_NOTEQUAL) {
358 set_true_false_states_expr(my_size_id, str, NULL, alloc_state_num(val + 1));
359 return;
362 switch (expr->op) {
363 case '<':
364 case SPECIAL_UNSIGNED_LT:
365 if (strlen_left)
366 true_state = alloc_state_num(val);
367 else
368 false_state = alloc_state_num(val + 1);
369 break;
370 case SPECIAL_LTE:
371 case SPECIAL_UNSIGNED_LTE:
372 if (strlen_left)
373 true_state = alloc_state_num(val + 1);
374 else
375 false_state = alloc_state_num(val);
376 break;
377 case SPECIAL_GTE:
378 case SPECIAL_UNSIGNED_GTE:
379 if (strlen_left)
380 false_state = alloc_state_num(val);
381 else
382 true_state = alloc_state_num(val + 1);
383 break;
384 case '>':
385 case SPECIAL_UNSIGNED_GT:
386 if (strlen_left)
387 false_state = alloc_state_num(val + 1);
388 else
389 true_state = alloc_state_num(val);
390 break;
392 set_true_false_states_expr(my_size_id, str, true_state, false_state);
395 static struct expression *strip_ampersands(struct expression *expr)
397 struct symbol *type;
399 if (expr->type != EXPR_PREOP)
400 return expr;
401 if (expr->op != '&')
402 return expr;
403 type = get_type(expr->unop);
404 if (!type || type->type != SYM_ARRAY)
405 return expr;
406 return expr->unop;
409 static void match_array_assignment(struct expression *expr)
411 struct expression *left;
412 struct expression *right;
413 int array_size;
415 if (expr->op != '=')
416 return;
417 left = strip_expr(expr->left);
418 right = strip_expr(expr->right);
419 right = strip_ampersands(right);
420 array_size = get_array_size_bytes(right);
421 if (array_size)
422 set_state_expr(my_size_id, left, alloc_state_num(array_size));
425 static void info_record_alloction(struct expression *buffer, struct expression *size)
427 char *member;
428 long long val;
430 if (!option_info)
431 return;
432 member = get_member_name(buffer);
433 if (!member)
434 return;
435 if (!get_implied_value(size, &val))
436 val = -1;
437 sm_msg("info: '%s' allocated_buf_size %lld", member, val);
438 free_string(member);
441 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
443 int size_arg = PTR_INT(_size_arg);
444 struct expression *right;
445 struct expression *arg;
446 long long bytes;
448 right = strip_expr(expr->right);
449 arg = get_argument_from_call_expr(right->args, size_arg);
451 info_record_alloction(expr->left, arg);
453 if (!get_implied_value(arg, &bytes))
454 return;
455 set_state_expr(my_size_id, expr->left, alloc_state_num(bytes));
458 static void match_calloc(const char *fn, struct expression *expr, void *unused)
460 struct expression *right;
461 struct expression *arg;
462 long long elements;
463 long long size;
465 right = strip_expr(expr->right);
466 arg = get_argument_from_call_expr(right->args, 0);
467 if (!get_implied_value(arg, &elements))
468 return;
469 arg = get_argument_from_call_expr(right->args, 1);
470 if (!get_implied_value(arg, &size))
471 return;
472 set_state_expr(my_size_id, expr->left, alloc_state_num(elements * size));
475 static void match_strlen(const char *fn, struct expression *expr, void *unused)
477 struct expression *right;
478 struct expression *str;
479 struct expression *len_expr;
480 char *len_name;
481 struct smatch_state *state;
483 right = strip_expr(expr->right);
484 str = get_argument_from_call_expr(right->args, 0);
485 len_expr = strip_expr(expr->left);
487 len_name = get_variable_from_expr(len_expr, NULL);
488 if (!len_name)
489 return;
491 state = __alloc_smatch_state(0);
492 state->name = len_name;
493 state->data = len_expr;
494 set_state_expr(my_strlen_id, str, state);
497 static void match_limited(const char *fn, struct expression *expr, void *_limiter)
499 struct limiter *limiter = (struct limiter *)_limiter;
500 struct expression *dest;
501 struct expression *size_expr;
502 long long size;
504 dest = get_argument_from_call_expr(expr->args, limiter->buf_arg);
505 size_expr = get_argument_from_call_expr(expr->args, limiter->limit_arg);
506 if (!get_implied_max(size_expr, &size))
507 return;
508 set_state_expr(my_size_id, dest, alloc_state_num(size));
511 static void match_strcpy(const char *fn, struct expression *expr, void *unused)
513 struct expression fake_assign;
515 fake_assign.op = '=';
516 fake_assign.left = get_argument_from_call_expr(expr->args, 0);
517 fake_assign.right = get_argument_from_call_expr(expr->args, 1);
518 match_array_assignment(&fake_assign);
521 static void match_strndup(const char *fn, struct expression *expr, void *unused)
523 struct expression *fn_expr;
524 struct expression *size_expr;
525 long long size;
527 fn_expr = strip_expr(expr->right);
528 size_expr = get_argument_from_call_expr(fn_expr->args, 1);
529 if (!get_implied_max(size_expr, &size))
530 return;
532 /* It's easy to forget space for the NUL char */
533 size++;
534 set_state_expr(my_size_id, expr->left, alloc_state_num(size));
537 static void match_call(struct expression *expr)
539 char *name;
540 struct expression *arg;
541 int bytes;
542 int i;
544 name = get_fnptr_name(expr->fn);
545 if (!name)
546 return;
548 i = 0;
549 FOR_EACH_PTR(expr->args, arg) {
550 bytes = get_array_size_bytes(arg);
551 if (bytes > 1)
552 sm_msg("info: passes_buffer '%s' %d '$$' %d %s",
553 name, i, bytes,
554 is_static(expr->fn) ? "static" : "global");
555 i++;
556 } END_FOR_EACH_PTR(arg);
558 free_string(name);
561 static void struct_member_callback(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state)
563 if (state == &merged)
564 return;
565 sm_msg("info: passes_buffer '%s' %d '%s' %s %s", fn, param, printed_name, state->name, global_static);
568 static void match_func_end(struct symbol *sym)
570 memset(params_set, 0, sizeof(params_set));
573 void register_buf_size(int id)
575 my_size_id = id;
577 add_definition_db_callback(set_param_buf_size, BUF_SIZE);
579 add_function_assign_hook("malloc", &match_alloc, INT_PTR(0));
580 add_function_assign_hook("calloc", &match_calloc, NULL);
581 add_function_assign_hook("memdup", &match_alloc, INT_PTR(1));
582 if (option_project == PROJ_KERNEL) {
583 add_function_assign_hook("kmalloc", &match_alloc, INT_PTR(0));
584 add_function_assign_hook("kzalloc", &match_alloc, INT_PTR(0));
585 add_function_assign_hook("vmalloc", &match_alloc, INT_PTR(0));
586 add_function_assign_hook("__vmalloc", &match_alloc, INT_PTR(0));
587 add_function_assign_hook("kcalloc", &match_calloc, NULL);
588 add_function_assign_hook("kmalloc_array", &match_calloc, NULL);
589 add_function_assign_hook("drm_malloc_ab", &match_calloc, NULL);
590 add_function_assign_hook("drm_calloc_large", &match_calloc, NULL);
591 add_function_assign_hook("sock_kmalloc", &match_alloc, INT_PTR(1));
592 add_function_assign_hook("kmemdup", &match_alloc, INT_PTR(1));
593 add_function_assign_hook("kmemdup_user", &match_alloc, INT_PTR(1));
595 add_hook(&match_array_assignment, ASSIGNMENT_HOOK);
596 add_hook(&match_strlen_condition, CONDITION_HOOK);
597 add_function_assign_hook("strlen", &match_strlen, NULL);
599 add_function_assign_hook("strndup", match_strndup, NULL);
600 if (option_project == PROJ_KERNEL)
601 add_function_assign_hook("kstrndup", match_strndup, NULL);
603 add_hook(&match_func_end, END_FUNC_HOOK);
604 add_modification_hook(my_size_id, &set_undefined);
607 void register_strlen(int id)
609 my_strlen_id = id;
610 add_modification_hook(my_strlen_id, &set_undefined);
613 void register_buf_size_late(int id)
615 add_function_hook("strlcpy", &match_limited, &b0_l2);
616 add_function_hook("strlcat", &match_limited, &b0_l2);
617 add_function_hook("memscan", &match_limited, &b0_l2);
619 add_function_hook("strcpy", &match_strcpy, NULL);
621 if (option_info) {
622 add_hook(&match_call, FUNCTION_CALL_HOOK);
623 add_member_info_callback(my_size_id, struct_member_callback);