buf_size: pull get_size_from_initializer() into separate function
[smatch.git] / smatch_buf_size.c
blob5e03fb64dd07537433479c5cff295b3531c70ccd
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 get_initializer_size(struct expression *expr)
60 switch (expr->type) {
61 case EXPR_STRING:
62 return expr->string->length;
63 case EXPR_INITIALIZER: {
64 struct expression *tmp;
65 int i = 0;
66 int max = 0;
68 FOR_EACH_PTR(expr->expr_list, tmp) {
69 if (tmp->type == EXPR_INDEX && tmp->idx_to > max)
70 max = tmp->idx_to;
71 i++;
72 } END_FOR_EACH_PTR(tmp);
73 if (max)
74 return max + 1;
75 return i;
77 case EXPR_SYMBOL:
78 return get_array_size(expr);
80 return 0;
83 static float get_cast_ratio(struct expression *unstripped)
85 struct expression *start_expr;
86 struct symbol *start_type;
87 struct symbol *end_type;
88 int start_bytes = 0;
89 int end_bytes = 0;
91 start_expr = strip_expr(unstripped);
92 start_type = get_type(start_expr);
93 end_type = get_type(unstripped);
94 if (!start_type || !end_type)
95 return 1;
97 if (start_type->type == SYM_PTR)
98 start_bytes = (get_base_type(start_type))->ctype.alignment;
99 if (start_type->type == SYM_ARRAY)
100 start_bytes = (get_base_type(start_type))->bit_size / 8;
101 if (end_type->type == SYM_PTR)
102 end_bytes = (get_base_type(end_type))->ctype.alignment;
103 if (end_type->type == SYM_ARRAY)
104 end_bytes = (get_base_type(end_type))->bit_size / 8;
106 if (!start_bytes || !end_bytes)
107 return 1;
108 return start_bytes / end_bytes;
111 static int db_size;
112 static int db_size_callback(void *unused, int argc, char **argv, char **azColName)
114 db_size = atoi(argv[0]);
115 return 0;
118 static int size_from_db(struct expression *expr)
120 char *name;
122 if (!option_spammy)
123 return 0;
125 name = get_member_name(expr);
126 if (!name)
127 return 0;
129 db_size = 0;
130 run_sql(db_size_callback, "select size from type_size where type = '%s'",
131 name);
132 return db_size;
135 static int get_real_array_size(struct expression *expr)
137 struct symbol *type;
138 float cast_ratio;
139 int ret;
141 type = get_type(expr);
142 if (!type || type->type != SYM_ARRAY)
143 return 0;
145 cast_ratio = get_cast_ratio(expr);
147 ret = get_expression_value(type->array_size);
148 /* Dynamically sized array are -1 in sparse */
149 if (ret <= 0)
150 return 0;
151 /* People put one element arrays on the end of structs */
152 if (ret == 1)
153 return 0;
155 return ret * cast_ratio;
158 static int get_size_from_initializer(struct expression *expr)
160 float cast_ratio;
162 if (expr->type != EXPR_SYMBOL || !expr->symbol->initializer)
163 return 0;
164 if (expr->symbol->initializer == expr) /* int a = a; */
165 return 0;
166 cast_ratio = get_cast_ratio(expr);
167 return get_initializer_size(expr->symbol->initializer) * cast_ratio;
170 static int get_stored_size(struct expression *expr)
172 struct symbol *type;
173 struct smatch_state *state;
174 float cast_ratio;
175 int ret;
177 type = get_type(expr);
178 if (!type)
179 return 0;
181 cast_ratio = get_cast_ratio(expr);
183 state = get_state_expr(my_size_id, expr);
184 if (!state || !state->data)
185 return 0;
186 if (type->type == SYM_PTR)
187 type = get_base_type(type);
188 if (!type->ctype.alignment)
189 return 0;
190 ret = PTR_INT(state->data) / type->ctype.alignment;
191 return ret * cast_ratio;
194 int get_array_size(struct expression *expr)
196 struct smatch_state *state;
197 int ret = 0;
198 long long len;
200 expr = strip_expr(expr);
201 if (!expr)
202 return 0;
204 if (expr->type == EXPR_STRING)
205 return expr->string->length;
207 ret = get_real_array_size(expr);
208 if (ret)
209 return ret;
211 ret = get_stored_size(expr);
212 if (ret)
213 return ret;
215 ret = get_size_from_initializer(expr);
216 if (ret)
217 return ret;
219 state = get_state_expr(my_strlen_id, expr);
220 if (!state || !state->data)
221 return 0;
222 if (get_implied_max((struct expression *)state->data, &len))
223 return len + 1; /* add one because strlen doesn't include the NULL */
224 return 0;
227 int get_array_size_bytes(struct expression *expr)
229 struct symbol *tmp;
230 int array_size;
231 int element_size;
233 if (!expr)
234 return 0;
236 if (expr->type == EXPR_STRING)
237 return expr->string->length;
239 tmp = get_type(expr);
240 if (!tmp)
241 return 0;
243 if (tmp->type == SYM_ARRAY) {
244 tmp = get_base_type(tmp);
245 element_size = tmp->bit_size / 8;
246 } else if (tmp->type == SYM_PTR) {
247 tmp = get_base_type(tmp);
248 element_size = tmp->ctype.alignment;
249 } else {
250 return 0;
252 array_size = get_array_size(expr);
253 if (array_size)
254 return array_size * element_size;
256 return size_from_db(expr);
259 static void match_strlen_condition(struct expression *expr)
261 struct expression *left;
262 struct expression *right;
263 struct expression *str = NULL;
264 int strlen_left = 0;
265 int strlen_right = 0;
266 long long val;
267 struct smatch_state *true_state = NULL;
268 struct smatch_state *false_state = NULL;
270 if (expr->type != EXPR_COMPARE)
271 return;
272 left = strip_expr(expr->left);
273 right = strip_expr(expr->right);
275 if (left->type == EXPR_CALL && sym_name_is("strlen", left->fn)) {
276 str = get_argument_from_call_expr(left->args, 0);
277 strlen_left = 1;
279 if (right->type == EXPR_CALL && sym_name_is("strlen", right->fn)) {
280 str = get_argument_from_call_expr(right->args, 0);
281 strlen_right = 1;
284 if (!strlen_left && !strlen_right)
285 return;
286 if (strlen_left && strlen_right)
287 return;
289 if (strlen_left) {
290 if (!get_value(right, &val))
291 return;
293 if (strlen_right) {
294 if (!get_value(left, &val))
295 return;
298 if (expr->op == SPECIAL_EQUAL) {
299 set_true_false_states_expr(my_size_id, str, alloc_state_num(val + 1), NULL);
300 return;
302 if (expr->op == SPECIAL_NOTEQUAL) {
303 set_true_false_states_expr(my_size_id, str, NULL, alloc_state_num(val + 1));
304 return;
307 switch (expr->op) {
308 case '<':
309 case SPECIAL_UNSIGNED_LT:
310 if (strlen_left)
311 true_state = alloc_state_num(val);
312 else
313 false_state = alloc_state_num(val + 1);
314 break;
315 case SPECIAL_LTE:
316 case SPECIAL_UNSIGNED_LTE:
317 if (strlen_left)
318 true_state = alloc_state_num(val + 1);
319 else
320 false_state = alloc_state_num(val);
321 break;
322 case SPECIAL_GTE:
323 case SPECIAL_UNSIGNED_GTE:
324 if (strlen_left)
325 false_state = alloc_state_num(val);
326 else
327 true_state = alloc_state_num(val + 1);
328 break;
329 case '>':
330 case SPECIAL_UNSIGNED_GT:
331 if (strlen_left)
332 false_state = alloc_state_num(val + 1);
333 else
334 true_state = alloc_state_num(val);
335 break;
337 set_true_false_states_expr(my_size_id, str, true_state, false_state);
340 static struct expression *strip_ampersands(struct expression *expr)
342 struct symbol *type;
344 if (expr->type != EXPR_PREOP)
345 return expr;
346 if (expr->op != '&')
347 return expr;
348 type = get_type(expr->unop);
349 if (!type || type->type != SYM_ARRAY)
350 return expr;
351 return expr->unop;
354 static void match_array_assignment(struct expression *expr)
356 struct expression *left;
357 struct expression *right;
358 int array_size;
360 if (expr->op != '=')
361 return;
362 left = strip_expr(expr->left);
363 right = strip_expr(expr->right);
364 right = strip_ampersands(right);
365 array_size = get_array_size_bytes(right);
366 if (array_size)
367 set_state_expr(my_size_id, left, alloc_state_num(array_size));
370 static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
372 int size_arg = PTR_INT(_size_arg);
373 struct expression *right;
374 struct expression *arg;
375 long long bytes;
377 right = strip_expr(expr->right);
378 arg = get_argument_from_call_expr(right->args, size_arg);
379 if (!get_implied_value(arg, &bytes))
380 return;
382 set_state_expr(my_size_id, expr->left, alloc_state_num(bytes));
384 if (option_info) {
385 char *member = get_member_name(expr->left);
387 if (member)
388 sm_msg("info: '%s' allocated_buf_size %lld",
389 member, bytes);
390 free_string(member);
394 static void match_calloc(const char *fn, struct expression *expr, void *unused)
396 struct expression *right;
397 struct expression *arg;
398 long long elements;
399 long long size;
401 right = strip_expr(expr->right);
402 arg = get_argument_from_call_expr(right->args, 0);
403 if (!get_implied_value(arg, &elements))
404 return;
405 arg = get_argument_from_call_expr(right->args, 1);
406 if (!get_implied_value(arg, &size))
407 return;
408 set_state_expr(my_size_id, expr->left, alloc_state_num(elements * size));
411 static void match_strlen(const char *fn, struct expression *expr, void *unused)
413 struct expression *right;
414 struct expression *str;
415 struct expression *len_expr;
416 char *len_name;
417 struct smatch_state *state;
419 right = strip_expr(expr->right);
420 str = get_argument_from_call_expr(right->args, 0);
421 len_expr = strip_expr(expr->left);
423 len_name = get_variable_from_expr(len_expr, NULL);
424 if (!len_name)
425 return;
427 state = __alloc_smatch_state(0);
428 state->name = len_name;
429 state->data = len_expr;
430 set_state_expr(my_strlen_id, str, state);
433 static void match_limited(const char *fn, struct expression *expr, void *_limiter)
435 struct limiter *limiter = (struct limiter *)_limiter;
436 struct expression *dest;
437 struct expression *size_expr;
438 long long size;
440 dest = get_argument_from_call_expr(expr->args, limiter->buf_arg);
441 size_expr = get_argument_from_call_expr(expr->args, limiter->limit_arg);
442 if (!get_implied_max(size_expr, &size))
443 return;
444 set_state_expr(my_size_id, dest, alloc_state_num(size));
447 static void match_strcpy(const char *fn, struct expression *expr, void *unused)
449 struct expression fake_assign;
451 fake_assign.op = '=';
452 fake_assign.left = get_argument_from_call_expr(expr->args, 0);
453 fake_assign.right = get_argument_from_call_expr(expr->args, 1);
454 match_array_assignment(&fake_assign);
457 static void match_strndup(const char *fn, struct expression *expr, void *unused)
459 struct expression *fn_expr;
460 struct expression *size_expr;
461 long long size;
463 fn_expr = strip_expr(expr->right);
464 size_expr = get_argument_from_call_expr(fn_expr->args, 1);
465 if (!get_implied_max(size_expr, &size))
466 return;
468 /* It's easy to forget space for the NUL char */
469 size++;
470 set_state_expr(my_size_id, expr->left, alloc_state_num(size));
473 static void match_call(struct expression *expr)
475 char *name;
476 struct expression *arg;
477 int bytes;
478 int i;
480 name = get_fnptr_name(expr->fn);
481 if (!name)
482 return;
484 i = 0;
485 FOR_EACH_PTR(expr->args, arg) {
486 bytes = get_array_size_bytes(arg);
487 if (bytes > 1)
488 sm_msg("info: passes_buffer '%s' %d '$$' %d %s",
489 name, i, bytes,
490 is_static(expr->fn) ? "static" : "global");
491 i++;
492 } END_FOR_EACH_PTR(arg);
494 free_string(name);
497 static void struct_member_callback(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state)
499 if (state == &merged)
500 return;
501 sm_msg("info: passes_buffer '%s' %d '%s' %s %s", fn, param, printed_name, state->name, global_static);
504 static void match_func_end(struct symbol *sym)
506 memset(params_set, 0, sizeof(params_set));
509 void register_buf_size(int id)
511 my_size_id = id;
513 add_definition_db_callback(set_param_buf_size, BUF_SIZE);
515 add_function_assign_hook("malloc", &match_alloc, INT_PTR(0));
516 add_function_assign_hook("calloc", &match_calloc, NULL);
517 add_function_assign_hook("memdup", &match_alloc, INT_PTR(1));
518 if (option_project == PROJ_KERNEL) {
519 add_function_assign_hook("kmalloc", &match_alloc, INT_PTR(0));
520 add_function_assign_hook("kzalloc", &match_alloc, INT_PTR(0));
521 add_function_assign_hook("vmalloc", &match_alloc, INT_PTR(0));
522 add_function_assign_hook("__vmalloc", &match_alloc, INT_PTR(0));
523 add_function_assign_hook("kcalloc", &match_calloc, NULL);
524 add_function_assign_hook("drm_malloc_ab", &match_calloc, NULL);
525 add_function_assign_hook("drm_calloc_large", &match_calloc, NULL);
526 add_function_assign_hook("kmemdup", &match_alloc, INT_PTR(1));
527 add_function_assign_hook("kmemdup_user", &match_alloc, INT_PTR(1));
529 add_hook(&match_array_assignment, ASSIGNMENT_HOOK);
530 add_hook(&match_strlen_condition, CONDITION_HOOK);
531 add_function_assign_hook("strlen", &match_strlen, NULL);
533 add_function_hook("strlcpy", &match_limited, &b0_l2);
534 add_function_hook("strlcat", &match_limited, &b0_l2);
535 add_function_hook("memscan", &match_limited, &b0_l2);
537 add_function_hook("strcpy", &match_strcpy, NULL);
539 add_function_assign_hook("strndup", match_strndup, NULL);
540 if (option_project == PROJ_KERNEL)
541 add_function_assign_hook("kstrndup", match_strndup, NULL);
543 if (option_info) {
544 add_hook(&match_call, FUNCTION_CALL_HOOK);
545 add_member_info_callback(my_size_id, struct_member_callback);
548 add_hook(&match_func_end, END_FUNC_HOOK);
549 add_modification_hook(my_size_id, &set_undefined);
552 void register_strlen(int id)
554 my_strlen_id = id;
555 add_modification_hook(my_strlen_id, &set_undefined);