2 * sparse/check_deference.c
4 * Copyright (C) 2006 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
13 #include "smatch_slist.h"
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");
26 snprintf(buff
, 255, "(%lld)", num
);
28 snprintf(buff
, 255, "%lld", num
);
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
;
45 static int malloc_size(struct expression
*expr
)
48 struct expression
*arg
;
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);
59 return get_value(arg
) * 8;
62 } else if (expr
->type
== EXPR_STRING
&& expr
->string
) {
63 return expr
->string
->length
* 8;
68 static void match_declaration(struct symbol
*sym
)
70 struct symbol
*base_type
;
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
));
83 size
= malloc_size(sym
->initializer
);
85 set_state(name
, my_id
, NULL
, alloc_my_state(size
));
90 static int get_array_size(struct expression
*expr
)
94 struct smatch_state
*state
;
97 if (expr
->type
!= EXPR_SYMBOL
)
99 name
= get_variable_from_expr(expr
, NULL
);
102 state
= get_state(name
, my_id
, NULL
);
103 if (!state
|| !state
->data
)
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
;
114 static void array_check(struct expression
*expr
)
116 struct expression
*dest
;
118 struct expression
*offset
;
122 expr
= strip_expr(expr
);
126 dest
= get_array_name(expr
);
127 array_size
= get_array_size(dest
);
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
);
140 static void match_assignment(struct expression
*expr
)
143 name
= get_variable_from_expr(expr
->left
, NULL
);
146 if (malloc_size(expr
->right
) > 0)
147 set_state(name
, my_id
, NULL
, alloc_my_state(malloc_size(expr
->right
)));
151 static void match_strcpy(const char *fn
, struct expression
*expr
,
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
;
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
)
173 data_state
= get_state(data_name
, my_id
, NULL
);
174 if (!data_state
|| !data_state
->data
)
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
);
182 free_string(dest_name
);
183 free_string(data_name
);
186 static void match_limitted(const char *fn
, struct expression
*expr
,
189 struct expression
*dest
;
190 struct expression
*data
;
191 char *dest_name
= NULL
;
192 struct smatch_state
*state
;
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
)
204 has
= *(int *)state
->data
/ 8;
206 smatch_msg("error: %s too small for %d bytes.", dest_name
,
209 free_string(dest_name
);
212 void check_overflow(int 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);