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"
14 #include "smatch_extra.h"
21 static int my_decl_id
;
22 static int my_used_id
;
24 static struct symbol
*this_func
;
26 static void match_function_def(struct symbol
*sym
)
31 static void print_args(struct expression
*expr
, int size
)
42 name
= get_variable_from_expr(expr
, &sym
);
47 FOR_EACH_PTR(this_func
->ctype
.base_type
->arguments
, arg
) {
48 arg_name
= (arg
->ident
?arg
->ident
->name
:"-");
49 if (sym
== arg
&& !strcmp(name
, arg_name
)) {
50 sm_info("param %d array index. size %d", i
, size
);
54 } END_FOR_EACH_PTR(arg
);
59 static char *alloc_num(long long num
)
61 static char buff
[256];
63 if (num
== whole_range
.min
) {
64 snprintf(buff
, 255, "min");
65 } else if (num
== whole_range
.max
) {
66 snprintf(buff
, 255, "max");
68 snprintf(buff
, 255, "(%lld)", num
);
70 snprintf(buff
, 255, "%lld", num
);
73 return alloc_sname(buff
);
76 static void delete(const char *name
, struct symbol
*sym
, struct expression
*expr
, void *unused
)
78 delete_state(my_used_id
, name
, sym
);
81 static struct smatch_state
*alloc_my_state(int val
)
83 struct smatch_state
*state
;
85 state
= malloc(sizeof(*state
));
86 state
->name
= alloc_num(val
);
87 state
->data
= malloc(sizeof(int));
88 *(int *)state
->data
= val
;
92 static void match_declaration(struct symbol
*sym
)
94 struct symbol
*base_type
;
101 name
= sym
->ident
->name
;
102 base_type
= get_base_type(sym
);
104 if (base_type
->type
== SYM_ARRAY
&& base_type
->bit_size
> 0) {
105 set_state(my_decl_id
, name
, NULL
, alloc_my_state(base_type
->bit_size
));
107 if (sym
->initializer
&&
108 sym
->initializer
->type
== EXPR_STRING
&&
109 sym
->initializer
->string
) {
110 size
= sym
->initializer
->string
->length
* 8;
111 set_state(my_decl_id
, name
, NULL
, alloc_my_state(size
));
116 static int is_last_struct_member(struct expression
*expr
)
118 struct ident
*member
;
119 struct symbol
*struct_sym
;
122 if (!expr
|| expr
->type
!= EXPR_DEREF
)
125 member
= expr
->member
;
126 struct_sym
= get_type(expr
->deref
);
129 if (struct_sym
->type
== SYM_PTR
)
130 struct_sym
= get_base_type(struct_sym
);
131 FOR_EACH_PTR_REVERSE(struct_sym
->symbol_list
, tmp
) {
132 if (tmp
->ident
== member
)
135 } END_FOR_EACH_PTR_REVERSE(tmp
);
140 static int get_array_size(struct expression
*expr
)
144 struct smatch_state
*state
;
147 tmp
= get_type(expr
);
150 if (tmp
->type
== SYM_ARRAY
) {
151 ret
= get_expression_value(tmp
->array_size
);
152 if (ret
== 1 && is_last_struct_member(expr
))
156 name
= get_variable_from_expr(expr
, NULL
);
159 state
= get_state(my_decl_id
, name
, NULL
);
160 if (!state
|| !state
->data
)
162 if (tmp
->type
== SYM_PTR
)
163 tmp
= get_base_type(tmp
);
164 if (!tmp
->ctype
.alignment
)
166 ret
= *(int *)state
->data
/ 8 / tmp
->ctype
.alignment
;
172 extern int check_assigned_expr_id
;
173 static void print_assigned_expr(struct expression
*expr
)
176 struct state_list
*slist
;
177 struct sm_state
*tmp
;
180 name
= get_variable_from_expr(expr
, NULL
);
181 slist
= get_possible_states_expr(check_assigned_expr_id
, expr
);
182 FOR_EACH_PTR(slist
, tmp
) {
183 if (tmp
->state
== &undefined
|| tmp
->state
== &merged
)
185 smatch_msg("debug: unknown initializer %s = %s", name
, show_state(tmp
->state
));
186 } END_FOR_EACH_PTR(tmp
);
191 static void array_check(struct expression
*expr
)
193 struct expression
*dest
;
195 struct expression
*offset
;
199 expr
= strip_expr(expr
);
203 dest
= get_array_name(expr
);
204 array_size
= get_array_size(dest
);
206 name
= get_variable_from_expr(dest
, NULL
);
209 // smatch_msg("debug: array '%s' unknown size", name);
210 print_assigned_expr(dest
);
214 offset
= get_array_offset(expr
);
215 if (!get_fuzzy_max(offset
, &max
)) {
216 if (getting_address())
218 name
= get_variable_from_expr(offset
, NULL
);
221 // smatch_msg("debug: offset '%s' unknown", name);
222 set_state_expr(my_used_id
, offset
, alloc_state_num(array_size
));
223 add_modification_hook(my_used_id
, name
, &delete, NULL
);
224 print_args(offset
, array_size
);
226 } else if (array_size
<= max
) {
227 const char *level
= "error";
229 if (getting_address())
232 name
= get_variable_from_expr_complex(dest
, NULL
);
234 blast. smatch can't figure out glibc's strcmp __strcmp_cg()
235 so it prints an error every time you compare to a string
236 literal array with 4 or less chars. */
237 if (name
&& strcmp(name
, "__s1") && strcmp(name
, "__s2"))
238 sm_msg("%s: buffer overflow '%s' %d <= %lld", level
, name
, array_size
, max
);
243 static void match_condition(struct expression
*expr
)
247 struct state_list
*slist
;
248 struct sm_state
*tmp
;
251 if (!expr
|| expr
->type
!= EXPR_COMPARE
)
253 if (get_implied_value(expr
->left
, &val
))
255 else if (get_implied_value(expr
->right
, &val
))
261 slist
= get_possible_states_expr(my_used_id
, expr
->right
);
263 slist
= get_possible_states_expr(my_used_id
, expr
->left
);
266 FOR_EACH_PTR(slist
, tmp
) {
267 if (tmp
->state
== &merged
)
269 boundary
= (int)tmp
->state
->data
;
271 if (boundary
< 1 && boundary
> -1) {
274 name
= get_variable_from_expr(left
?expr
->right
:expr
->left
, NULL
);
275 sm_msg("error: testing array offset '%s' after use.", name
);
278 } END_FOR_EACH_PTR(tmp
);
282 static void match_string_assignment(struct expression
*expr
)
284 struct expression
*left
;
285 struct expression
*right
;
288 left
= strip_expr(expr
->left
);
289 right
= strip_expr(expr
->right
);
290 name
= get_variable_from_expr(left
, NULL
);
293 if (right
->type
!= EXPR_STRING
|| !right
->string
)
295 set_state(my_decl_id
, name
, NULL
,
296 alloc_my_state(right
->string
->length
* 8));
301 static void match_malloc(const char *fn
, struct expression
*expr
, void *unused
)
304 struct expression
*right
;
305 struct expression
*arg
;
308 name
= get_variable_from_expr(expr
->left
, NULL
);
312 right
= strip_expr(expr
->right
);
313 arg
= get_argument_from_call_expr(right
->args
, 0);
314 if (!get_implied_value(arg
, &bytes
))
316 set_state(my_decl_id
, name
, NULL
, alloc_my_state(bytes
* 8));
321 static void match_strcpy(const char *fn
, struct expression
*expr
,
324 struct expression
*dest
;
325 struct expression
*data
;
326 char *dest_name
= NULL
;
327 char *data_name
= NULL
;
328 struct smatch_state
*dest_state
;
329 struct smatch_state
*data_state
;
333 dest
= get_argument_from_call_expr(expr
->args
, 0);
334 dest_name
= get_variable_from_expr(dest
, NULL
);
336 data
= get_argument_from_call_expr(expr
->args
, 1);
337 data_name
= get_variable_from_expr(data
, NULL
);
339 dest_state
= get_state(my_decl_id
, dest_name
, NULL
);
340 if (!dest_state
|| !dest_state
->data
)
343 data_state
= get_state(my_decl_id
, data_name
, NULL
);
344 if (!data_state
|| !data_state
->data
)
346 dest_size
= *(int *)dest_state
->data
/ 8;
347 data_size
= *(int *)data_state
->data
/ 8;
348 if (dest_size
< data_size
)
349 sm_msg("error: %s (%d) too large for %s (%d)", data_name
,
350 data_size
, dest_name
, dest_size
);
352 free_string(dest_name
);
353 free_string(data_name
);
356 static void match_limitted(const char *fn
, struct expression
*expr
,
359 struct expression
*dest
;
360 struct expression
*data
;
361 char *dest_name
= NULL
;
362 struct smatch_state
*state
;
366 dest
= get_argument_from_call_expr(expr
->args
, 0);
367 dest_name
= get_variable_from_expr(dest
, NULL
);
369 data
= get_argument_from_call_expr(expr
->args
, PTR_INT(limit_arg
));
370 if (!get_value(data
, &needed
))
372 state
= get_state(my_decl_id
, dest_name
, NULL
);
373 if (!state
|| !state
->data
)
375 has
= *(int *)state
->data
/ 8;
377 sm_msg("error: %s too small for %lld bytes.", dest_name
,
380 free_string(dest_name
);
383 static void match_array_func(const char *fn
, struct expression
*expr
, void *info
)
385 struct bound
*bound_info
= (struct bound
*)info
;
386 struct expression
*arg
;
389 arg
= get_argument_from_call_expr(expr
->args
, bound_info
->param
);
390 if (!get_implied_value(arg
, &offset
))
392 if (offset
>= bound_info
->size
)
393 sm_msg("error: buffer overflow calling %s. param %d. %lld >= %d", fn
, bound_info
->param
, offset
, bound_info
->size
);
396 static void register_array_funcs(void)
400 struct bound
*bound_info
;
402 token
= get_tokens_file("kernel.array_bounds");
405 if (token_type(token
) != TOKEN_STREAMBEGIN
)
408 while (token_type(token
) != TOKEN_STREAMEND
) {
409 bound_info
= malloc(sizeof(*bound_info
));
410 if (token_type(token
) != TOKEN_IDENT
)
412 func
= show_ident(token
->ident
);
414 if (token_type(token
) != TOKEN_NUMBER
)
416 bound_info
->param
= atoi(token
->number
);
418 if (token_type(token
) != TOKEN_NUMBER
)
420 bound_info
->size
= atoi(token
->number
);
421 add_function_hook(func
, &match_array_func
, bound_info
);
427 void check_overflow(int id
)
430 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
431 add_hook(&match_declaration
, DECLARATION_HOOK
);
432 add_hook(&array_check
, OP_HOOK
);
433 add_hook(&match_string_assignment
, ASSIGNMENT_HOOK
);
434 add_hook(&match_condition
, CONDITION_HOOK
);
435 add_function_assign_hook("malloc", &match_malloc
, NULL
);
436 add_function_hook("strcpy", &match_strcpy
, NULL
);
437 add_function_hook("strncpy", &match_limitted
, (void *)2);
438 if (option_project
== PROJ_KERNEL
) {
439 add_function_assign_hook("kmalloc", &match_malloc
, NULL
);
440 add_function_assign_hook("kzalloc", &match_malloc
, NULL
);
441 add_function_assign_hook("vmalloc", &match_malloc
, NULL
);
442 add_function_hook("copy_to_user", &match_limitted
, (void *)2);
443 add_function_hook("copy_from_user", &match_limitted
, (void *)2);
445 register_array_funcs();
448 void register_check_overflow_again(int id
)