Remove optimization.
[smatch.git] / check_overflow.c
blobcfc1b34546a3858aacd35fc93e0e7632c042827b
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 static int my_id;
17 static char *alloc_num(long long num)
19 static char buff[256];
21 if (num == whole_range.min) {
22 snprintf(buff, 255, "min");
23 } else if (num == whole_range.max) {
24 snprintf(buff, 255, "max");
25 } else if (num < 0) {
26 snprintf(buff, 255, "(%lld)", num);
27 } else {
28 snprintf(buff, 255, "%lld", num);
30 buff[255] = '\0';
31 return alloc_sname(buff);
34 static struct smatch_state *alloc_my_state(int val)
36 struct smatch_state *state;
38 state = malloc(sizeof(*state));
39 state->name = alloc_num(val);
40 state->data = malloc(sizeof(int));
41 *(int *)state->data = val;
42 return state;
45 static int malloc_size(struct expression *expr)
47 char *name;
48 struct expression *arg;
50 if (!expr)
51 return 0;
53 expr = strip_expr(expr);
54 if (expr->type == EXPR_CALL) {
55 name = get_variable_from_expr(expr->fn, NULL);
56 if (name && !strcmp(name, "kmalloc")) {
57 arg = get_argument_from_call_expr(expr->args, 0);
58 free_string(name);
59 return get_value(arg) * 8;
61 free_string(name);
62 } else if (expr->type == EXPR_STRING && expr->string) {
63 return expr->string->length * 8;
65 return 0;
68 static void match_declaration(struct symbol *sym)
70 struct symbol *base_type;
71 char *name;
72 int size;
74 if (!sym->ident)
75 return;
77 name = sym->ident->name;
78 base_type = get_base_type(sym);
80 if (base_type->type == SYM_ARRAY && base_type->bit_size > 0) {
81 set_state(name, my_id, NULL, alloc_my_state(base_type->bit_size));
82 } else {
83 size = malloc_size(sym->initializer);
84 if (size > 0)
85 set_state(name, my_id, NULL, alloc_my_state(size));
90 static int get_array_size(struct expression *expr)
92 char *name;
93 struct symbol *tmp;
94 struct smatch_state *state;
95 int ret = 0;
97 if (expr->type != EXPR_SYMBOL)
98 return 0;
99 name = get_variable_from_expr(expr, NULL);
100 if (!name)
101 return 0;
102 state = get_state(name, my_id, NULL);
103 if (!state || !state->data)
104 goto free;
105 tmp = get_base_type(expr->symbol);
106 if (tmp->type == SYM_PTR)
107 tmp = get_base_type(tmp);
108 ret = *(int *)state->data / 8 / tmp->ctype.alignment;
109 free:
110 free_string(name);
111 return ret;
114 static void array_check(struct expression *expr)
116 struct expression *dest;
117 int array_size;
118 struct expression *offset;
119 int max;
120 char *name;
122 expr = strip_expr(expr);
123 if (!is_array(expr))
124 return;
126 dest = get_array_name(expr);
127 array_size = get_array_size(dest);
128 if (!array_size)
129 return;
131 offset = get_array_offset(expr);
132 max = get_implied_max(offset);
133 if (array_size <= max) {
134 name = get_variable_from_expr(dest, NULL);
135 smatch_msg("error: buffer overflow '%s' %d <= %d", name, array_size, max);
136 free_string(name);
140 static void match_assignment(struct expression *expr)
142 char *name;
143 name = get_variable_from_expr(expr->left, NULL);
144 if (!name)
145 return;
146 if (malloc_size(expr->right) > 0)
147 set_state(name, my_id, NULL, alloc_my_state(malloc_size(expr->right)));
148 free_string(name);
151 static void match_strcpy(const char *fn, struct expression *expr,
152 void *unused)
154 struct expression *dest;
155 struct expression *data;
156 char *dest_name = NULL;
157 char *data_name = NULL;
158 struct smatch_state *dest_state;
159 struct smatch_state *data_state;
160 int dest_size;
161 int data_size;
163 dest = get_argument_from_call_expr(expr->args, 0);
164 dest_name = get_variable_from_expr(dest, NULL);
166 data = get_argument_from_call_expr(expr->args, 1);
167 data_name = get_variable_from_expr(data, NULL);
169 dest_state = get_state(dest_name, my_id, NULL);
170 if (!dest_state || !dest_state->data)
171 goto free;
173 data_state = get_state(data_name, my_id, NULL);
174 if (!data_state || !data_state->data)
175 goto free;
176 dest_size = *(int *)dest_state->data / 8;
177 data_size = *(int *)data_state->data / 8;
178 if (dest_size < data_size)
179 smatch_msg("error: %s (%d) too large for %s (%d)", data_name,
180 data_size, dest_name, dest_size);
181 free:
182 free_string(dest_name);
183 free_string(data_name);
186 static void match_limitted(const char *fn, struct expression *expr,
187 void *limit_arg)
189 struct expression *dest;
190 struct expression *data;
191 char *dest_name = NULL;
192 struct smatch_state *state;
193 int needed;
194 int has;
196 dest = get_argument_from_call_expr(expr->args, 0);
197 dest_name = get_variable_from_expr(dest, NULL);
199 data = get_argument_from_call_expr(expr->args, PTR_INT(limit_arg));
200 needed = get_value(data);
201 state = get_state(dest_name, my_id, NULL);
202 if (!state || !state->data)
203 goto free;
204 has = *(int *)state->data / 8;
205 if (has < needed)
206 smatch_msg("error: %s too small for %d bytes.", dest_name,
207 needed);
208 free:
209 free_string(dest_name);
212 void check_overflow(int id)
214 my_id = id;
215 add_hook(&match_declaration, DECLARATION_HOOK);
216 add_hook(&array_check, OP_HOOK);
217 add_hook(&match_assignment, ASSIGNMENT_HOOK);
218 add_function_hook("strcpy", &match_strcpy, NULL);
219 add_function_hook("strncpy", &match_limitted, (void *)2);
220 add_function_hook("copy_to_user", &match_limitted, (void *)2);
221 add_function_hook("copy_from_user", &match_limitted, (void *)2);