cleanup: debug_implied_states => option_debug_implied
[smatch.git] / check_overflow.c
blob1711ffa044b12ce2d13fc151e9133b8bf9bfa57d
1 /*
2 * sparse/check_deference.c
4 * Copyright (C) 2006 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <stdlib.h>
11 #include "parse.h"
12 #include "smatch.h"
13 #include "smatch_slist.h"
15 struct bound {
16 int param;
17 int size;
20 static int my_id;
22 static struct symbol *this_func;
24 static void match_function_def(struct symbol *sym)
26 this_func = sym;
29 static void print_args(struct expression *expr, int size)
31 struct symbol *sym;
32 char *name;
33 struct symbol *arg;
34 const char *arg_name;
35 int i;
37 if (!option_spammy)
38 return;
40 name = get_variable_from_expr(expr, &sym);
41 if (!name || !sym)
42 goto free;
44 i = 0;
45 FOR_EACH_PTR(this_func->ctype.base_type->arguments, arg) {
46 arg_name = (arg->ident?arg->ident->name:"-");
47 if (sym == arg && !strcmp(name, arg_name)) {
48 sm_msg("param %d array index. size %d", i, size);
49 goto free;
51 i++;
52 } END_FOR_EACH_PTR(arg);
53 free:
54 free_string(name);
57 static char *alloc_num(long long num)
59 static char buff[256];
61 if (num == whole_range.min) {
62 snprintf(buff, 255, "min");
63 } else if (num == whole_range.max) {
64 snprintf(buff, 255, "max");
65 } else if (num < 0) {
66 snprintf(buff, 255, "(%lld)", num);
67 } else {
68 snprintf(buff, 255, "%lld", num);
70 buff[255] = '\0';
71 return alloc_sname(buff);
74 static struct smatch_state *alloc_my_state(int val)
76 struct smatch_state *state;
78 state = malloc(sizeof(*state));
79 state->name = alloc_num(val);
80 state->data = malloc(sizeof(int));
81 *(int *)state->data = val;
82 return state;
85 static void match_declaration(struct symbol *sym)
87 struct symbol *base_type;
88 char *name;
89 int size;
91 if (!sym->ident)
92 return;
94 name = sym->ident->name;
95 base_type = get_base_type(sym);
97 if (base_type->type == SYM_ARRAY && base_type->bit_size > 0) {
98 set_state(my_id, name, NULL, alloc_my_state(base_type->bit_size));
99 } else {
100 if (sym->initializer &&
101 sym->initializer->type == EXPR_STRING &&
102 sym->initializer->string) {
103 size = sym->initializer->string->length * 8;
104 set_state(my_id, name, NULL, alloc_my_state(size));
109 static int get_array_size(struct expression *expr)
111 char *name;
112 struct symbol *tmp;
113 struct smatch_state *state;
114 int ret = 0;
116 tmp = get_type(expr);
117 if (!tmp)
118 return ret;
119 if (tmp->type == SYM_ARRAY) {
120 ret = get_expression_value(tmp->array_size);
121 if (ret)
122 return ret;
124 name = get_variable_from_expr(expr, NULL);
125 if (!name)
126 return 0;
127 state = get_state(my_id, name, NULL);
128 if (!state || !state->data)
129 goto free;
130 if (tmp->type == SYM_PTR)
131 tmp = get_base_type(tmp);
132 if (!tmp->ctype.alignment)
133 goto free;
134 ret = *(int *)state->data / 8 / tmp->ctype.alignment;
135 free:
136 free_string(name);
137 return ret;
140 extern int check_assigned_expr_id;
141 static void print_assigned_expr(struct expression *expr)
143 #if 0
144 struct state_list *slist;
145 struct sm_state *tmp;
146 char *name;
148 name = get_variable_from_expr(expr, NULL);
149 slist = get_possible_states_expr(check_assigned_expr_id, expr);
150 FOR_EACH_PTR(slist, tmp) {
151 if (tmp->state == &undefined || tmp->state == &merged)
152 continue;
153 smatch_msg("debug: unknown initializer %s = %s", name, show_state(tmp->state));
154 } END_FOR_EACH_PTR(tmp);
155 free_string(name);
156 #endif
159 static void array_check(struct expression *expr)
161 struct expression *dest;
162 int array_size;
163 struct expression *offset;
164 long long max;
165 char *name;
167 expr = strip_expr(expr);
168 if (!is_array(expr))
169 return;
171 dest = get_array_name(expr);
172 array_size = get_array_size(dest);
173 if (!array_size) {
174 name = get_variable_from_expr(dest, NULL);
175 if (!name)
176 return;
177 // smatch_msg("debug: array '%s' unknown size", name);
178 print_assigned_expr(dest);
179 return;
182 offset = get_array_offset(expr);
183 if (!get_implied_max(offset, &max)) {
184 name = get_variable_from_expr(dest, NULL);
185 // smatch_msg("debug: offset '%s' unknown", name);
186 print_args(offset, array_size);
187 } else if (array_size <= max) {
188 name = get_variable_from_expr_complex(dest, NULL);
189 /*FIXME!!!!!!!!!!!
190 blast. smatch can't figure out glibc's strcmp __strcmp_cg()
191 so it prints an error every time you compare to a string
192 literal array with 4 or less chars. */
193 if (name && strcmp(name, "__s1") && strcmp(name, "__s2"))
194 sm_msg("error: buffer overflow '%s' %d <= %lld", name, array_size, max);
195 free_string(name);
199 static void match_string_assignment(struct expression *expr)
201 struct expression *left;
202 struct expression *right;
203 char *name;
205 left = strip_expr(expr->left);
206 right = strip_expr(expr->right);
207 name = get_variable_from_expr(left, NULL);
208 if (!name)
209 return;
210 if (right->type != EXPR_STRING || !right->string)
211 goto free;
212 set_state(my_id, name, NULL,
213 alloc_my_state(right->string->length * 8));
214 free:
215 free_string(name);
218 static void match_malloc(const char *fn, struct expression *expr, void *unused)
220 char *name;
221 struct expression *right;
222 struct expression *arg;
223 long long bytes;
225 name = get_variable_from_expr(expr->left, NULL);
226 if (!name)
227 return;
229 right = strip_expr(expr->right);
230 arg = get_argument_from_call_expr(right->args, 0);
231 if (!get_implied_value(arg, &bytes))
232 goto free;
233 set_state(my_id, name, NULL, alloc_my_state(bytes * 8));
234 free:
235 free_string(name);
238 static void match_strcpy(const char *fn, struct expression *expr,
239 void *unused)
241 struct expression *dest;
242 struct expression *data;
243 char *dest_name = NULL;
244 char *data_name = NULL;
245 struct smatch_state *dest_state;
246 struct smatch_state *data_state;
247 int dest_size;
248 int data_size;
250 dest = get_argument_from_call_expr(expr->args, 0);
251 dest_name = get_variable_from_expr(dest, NULL);
253 data = get_argument_from_call_expr(expr->args, 1);
254 data_name = get_variable_from_expr(data, NULL);
256 dest_state = get_state(my_id, dest_name, NULL);
257 if (!dest_state || !dest_state->data)
258 goto free;
260 data_state = get_state(my_id, data_name, NULL);
261 if (!data_state || !data_state->data)
262 goto free;
263 dest_size = *(int *)dest_state->data / 8;
264 data_size = *(int *)data_state->data / 8;
265 if (dest_size < data_size)
266 sm_msg("error: %s (%d) too large for %s (%d)", data_name,
267 data_size, dest_name, dest_size);
268 free:
269 free_string(dest_name);
270 free_string(data_name);
273 static void match_limitted(const char *fn, struct expression *expr,
274 void *limit_arg)
276 struct expression *dest;
277 struct expression *data;
278 char *dest_name = NULL;
279 struct smatch_state *state;
280 long long needed;
281 int has;
283 dest = get_argument_from_call_expr(expr->args, 0);
284 dest_name = get_variable_from_expr(dest, NULL);
286 data = get_argument_from_call_expr(expr->args, PTR_INT(limit_arg));
287 if (!get_value(data, &needed))
288 goto free;
289 state = get_state(my_id, dest_name, NULL);
290 if (!state || !state->data)
291 goto free;
292 has = *(int *)state->data / 8;
293 if (has < needed)
294 sm_msg("error: %s too small for %lld bytes.", dest_name,
295 needed);
296 free:
297 free_string(dest_name);
300 static void match_array_func(const char *fn, struct expression *expr, void *info)
302 struct bound *bound_info = (struct bound *)info;
303 struct expression *arg;
304 long long offset;
306 arg = get_argument_from_call_expr(expr->args, bound_info->param);
307 if (!get_implied_value(arg, &offset))
308 return;
309 if (offset >= bound_info->size)
310 sm_msg("buffer overflow calling %s. param %d. %lld >= %d", fn, bound_info->param, offset, bound_info->size);
313 static void register_array_funcs(void)
315 struct token *token;
316 const char *func;
317 struct bound *bound_info;
319 token = get_tokens_file("kernel.array_bounds");
320 if (!token)
321 return;
322 if (token_type(token) != TOKEN_STREAMBEGIN)
323 return;
324 token = token->next;
325 while (token_type(token) != TOKEN_STREAMEND) {
326 bound_info = malloc(sizeof(*bound_info));
327 if (token_type(token) != TOKEN_IDENT)
328 return;
329 func = show_ident(token->ident);
330 token = token->next;
331 if (token_type(token) != TOKEN_NUMBER)
332 return;
333 bound_info->param = atoi(token->number);
334 token = token->next;
335 if (token_type(token) != TOKEN_NUMBER)
336 return;
337 bound_info->size = atoi(token->number);
338 add_function_hook(func, &match_array_func, bound_info);
339 token = token->next;
341 clear_token_alloc();
344 void check_overflow(int id)
346 my_id = id;
347 add_hook(&match_function_def, FUNC_DEF_HOOK);
348 add_hook(&match_declaration, DECLARATION_HOOK);
349 add_hook(&array_check, OP_HOOK);
350 add_hook(&match_string_assignment, ASSIGNMENT_HOOK);
351 add_function_assign_hook("malloc", &match_malloc, NULL);
352 add_function_hook("strcpy", &match_strcpy, NULL);
353 add_function_hook("strncpy", &match_limitted, (void *)2);
354 if (option_project == PROJ_KERNEL) {
355 add_function_assign_hook("kmalloc", &match_malloc, NULL);
356 add_function_assign_hook("kzalloc", &match_malloc, NULL);
357 add_function_assign_hook("vmalloc", &match_malloc, NULL);
358 add_function_hook("copy_to_user", &match_limitted, (void *)2);
359 add_function_hook("copy_from_user", &match_limitted, (void *)2);
361 register_array_funcs();