2 * smatch/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"
22 * This check has two smatch IDs.
23 * my_size_id - used to store the size of arrays.
24 * my_used_id - keeps a record of array offsets that have been used.
25 * If the code checks that they are within bounds later on,
26 * we complain about using an array offset before checking
27 * that it is within bounds.
29 static int my_size_id
;
30 static int my_used_id
;
32 static struct symbol
*this_func
;
34 static int get_array_size(struct expression
*expr
);
36 static void match_function_def(struct symbol
*sym
)
41 static void print_args(struct expression
*expr
, int size
)
52 name
= get_variable_from_expr(expr
, &sym
);
57 FOR_EACH_PTR(this_func
->ctype
.base_type
->arguments
, arg
) {
58 arg_name
= (arg
->ident
?arg
->ident
->name
:"-");
59 if (sym
== arg
&& !strcmp(name
, arg_name
)) {
60 sm_info("param %d array index. size %d", i
, size
);
64 } END_FOR_EACH_PTR(arg
);
69 static char *alloc_num(long long num
)
71 static char buff
[256];
73 if (num
== whole_range
.min
)
74 snprintf(buff
, 255, "min");
75 else if (num
== whole_range
.max
)
76 snprintf(buff
, 255, "max");
78 snprintf(buff
, 255, "(%lld)", num
);
80 snprintf(buff
, 255, "%lld", num
);
83 return alloc_sname(buff
);
86 static void delete(const char *name
, struct symbol
*sym
, struct expression
*expr
, void *unused
)
88 delete_state(my_used_id
, name
, sym
);
91 static struct smatch_state
*alloc_my_state(int val
)
93 struct smatch_state
*state
;
95 state
= malloc(sizeof(*state
));
96 state
->name
= alloc_num(val
);
97 state
->data
= malloc(sizeof(int));
98 *(int *)state
->data
= val
;
102 static int is_last_struct_member(struct expression
*expr
)
104 struct ident
*member
;
105 struct symbol
*struct_sym
;
108 if (!expr
|| expr
->type
!= EXPR_DEREF
)
111 member
= expr
->member
;
112 struct_sym
= get_type(expr
->deref
);
115 if (struct_sym
->type
== SYM_PTR
)
116 struct_sym
= get_base_type(struct_sym
);
117 FOR_EACH_PTR_REVERSE(struct_sym
->symbol_list
, tmp
) {
118 if (tmp
->ident
== member
)
121 } END_FOR_EACH_PTR_REVERSE(tmp
);
125 static int get_initializer_size(struct expression
*expr
)
129 return expr
->string
->length
;
130 case EXPR_INITIALIZER
: {
131 struct expression
*tmp
;
135 FOR_EACH_PTR(expr
->expr_list
, tmp
) {
136 if (tmp
->type
== EXPR_INDEX
&& tmp
->idx_to
> max
)
139 } END_FOR_EACH_PTR(tmp
);
145 return get_array_size(expr
);
150 static int get_array_size(struct expression
*expr
)
153 struct smatch_state
*state
;
156 if (expr
->type
== EXPR_STRING
)
157 return expr
->string
->length
;
159 tmp
= get_type(expr
);
163 if (tmp
->type
== SYM_ARRAY
) {
164 ret
= get_expression_value(tmp
->array_size
);
165 if (ret
== 1 && is_last_struct_member(expr
))
171 state
= get_state_expr(my_size_id
, expr
);
172 if (state
== &merged
)
174 if (state
&& state
->data
) {
175 if (tmp
->type
== SYM_PTR
)
176 tmp
= get_base_type(tmp
);
177 if (!tmp
->ctype
.alignment
)
179 ret
= *(int *)state
->data
/ tmp
->ctype
.alignment
;
183 if (expr
->type
== EXPR_SYMBOL
&& expr
->symbol
->initializer
) {
184 if (expr
->symbol
->initializer
!= expr
) /* int a = a; */
185 return get_initializer_size(expr
->symbol
->initializer
);
190 static int get_array_size_bytes(struct expression
*expr
)
195 if (expr
->type
== EXPR_STRING
)
196 return expr
->string
->length
;
198 tmp
= get_type(expr
);
201 if (tmp
->type
== SYM_PTR
)
202 tmp
= get_base_type(tmp
);
203 array_size
= get_array_size(expr
);
204 return array_size
* tmp
->ctype
.alignment
;
207 static int definitely_just_used_as_limiter(struct expression
*array
, struct expression
*offset
)
210 struct expression
*tmp
;
214 if (!get_value(offset
, &val
))
216 if (get_array_size(array
) != val
)
219 FOR_EACH_PTR_REVERSE(big_expression_stack
, tmp
) {
224 if (tmp
->type
== EXPR_PREOP
&& tmp
->op
== '(')
226 if (tmp
->op
== '.' && !dot_ops
++)
228 if (step
== 1 && tmp
->op
== '&') {
232 if (step
== 2 && tmp
->type
== EXPR_COMPARE
)
235 } END_FOR_EACH_PTR_REVERSE(tmp
);
239 static void array_check(struct expression
*expr
)
241 struct expression
*array_expr
;
243 struct expression
*offset
;
247 expr
= strip_expr(expr
);
251 array_expr
= get_array_name(expr
);
252 array_size
= get_array_size(array_expr
);
256 offset
= get_array_offset(expr
);
257 if (!get_fuzzy_max(offset
, &max
)) {
258 if (getting_address())
260 set_state_expr(my_used_id
, offset
, alloc_state_num(array_size
));
261 add_modification_hook_expr(my_used_id
, offset
, &delete, NULL
);
262 print_args(offset
, array_size
);
263 } else if (array_size
<= max
) {
264 const char *level
= "error";
266 if (getting_address())
269 if (definitely_just_used_as_limiter(array_expr
, offset
))
272 name
= get_variable_from_expr_complex(array_expr
, NULL
);
273 /* Blast. Smatch can't figure out glibc's strcmp __strcmp_cg()
274 * so it prints an error every time you compare to a string
275 * literal array with 4 or less chars.
277 if (name
&& strcmp(name
, "__s1") && strcmp(name
, "__s2")) {
278 sm_msg("%s: buffer overflow '%s' %d <= %lld",
279 level
, name
, array_size
, max
);
285 static void match_condition(struct expression
*expr
)
289 struct state_list
*slist
;
290 struct sm_state
*tmp
;
293 if (!expr
|| expr
->type
!= EXPR_COMPARE
)
295 if (get_implied_value(expr
->left
, &val
))
297 else if (get_implied_value(expr
->right
, &val
))
303 slist
= get_possible_states_expr(my_used_id
, expr
->right
);
305 slist
= get_possible_states_expr(my_used_id
, expr
->left
);
308 FOR_EACH_PTR(slist
, tmp
) {
309 if (tmp
->state
== &merged
)
311 boundary
= (int)tmp
->state
->data
;
313 if (boundary
< 1 && boundary
> -1) {
316 name
= get_variable_from_expr((left
? expr
->right
: expr
->left
), NULL
);
317 sm_msg("error: testing array offset '%s' after use.", name
);
320 } END_FOR_EACH_PTR(tmp
);
323 static void match_string_assignment(struct expression
*expr
)
325 struct expression
*left
;
326 struct expression
*right
;
328 left
= strip_expr(expr
->left
);
329 right
= strip_expr(expr
->right
);
330 if (right
->type
!= EXPR_STRING
|| !right
->string
)
332 set_state_expr(my_size_id
, left
, alloc_my_state(right
->string
->length
));
335 static void match_array_assignment(struct expression
*expr
)
337 struct expression
*left
;
338 struct expression
*right
;
339 struct symbol
*left_type
;
344 left
= strip_expr(expr
->left
);
345 left_type
= get_type(left
);
346 if (!left_type
|| left_type
->type
!= SYM_PTR
)
348 left_type
= get_base_type(left_type
);
351 right
= strip_expr(expr
->right
);
352 array_size
= get_array_size(right
);
354 set_state_expr(my_size_id
, left
,
355 alloc_my_state(array_size
* left_type
->ctype
.alignment
));
358 static void match_malloc(const char *fn
, struct expression
*expr
, void *unused
)
360 struct expression
*right
;
361 struct expression
*arg
;
364 right
= strip_expr(expr
->right
);
365 arg
= get_argument_from_call_expr(right
->args
, 0);
366 if (!get_implied_value(arg
, &bytes
))
368 set_state_expr(my_size_id
, expr
->left
, alloc_my_state(bytes
));
371 static void match_strcpy(const char *fn
, struct expression
*expr
, void *unused
)
373 struct expression
*dest
;
374 struct expression
*data
;
375 char *dest_name
= NULL
;
376 char *data_name
= NULL
;
380 dest
= get_argument_from_call_expr(expr
->args
, 0);
381 data
= get_argument_from_call_expr(expr
->args
, 1);
382 dest_size
= get_array_size_bytes(dest
);
383 data_size
= get_array_size_bytes(data
);
384 if (!dest_size
|| !data_size
)
386 if (dest_size
>= data_size
)
389 dest_name
= get_variable_from_expr_complex(dest
, NULL
);
390 data_name
= get_variable_from_expr_complex(data
, NULL
);
391 sm_msg("error: %s() %s too large for %s (%d vs %d)",
392 fn
, data_name
, dest_name
, data_size
, dest_size
);
393 free_string(dest_name
);
394 free_string(data_name
);
397 static void match_limitted(const char *fn
, struct expression
*expr
, void *limit_arg
)
399 struct expression
*dest
;
400 struct expression
*data
;
401 char *dest_name
= NULL
;
405 dest
= get_argument_from_call_expr(expr
->args
, 0);
406 data
= get_argument_from_call_expr(expr
->args
, PTR_INT(limit_arg
));
407 if (!get_fuzzy_max(data
, &needed
))
409 has
= get_array_size_bytes(dest
);
415 dest_name
= get_variable_from_expr_complex(dest
, NULL
);
416 sm_msg("error: %s() %s too small (%d vs %lld)", fn
, dest_name
, has
, needed
);
417 free_string(dest_name
);
420 static void match_array_func(const char *fn
, struct expression
*expr
, void *info
)
422 struct bound
*bound_info
= (struct bound
*)info
;
423 struct expression
*arg
;
426 arg
= get_argument_from_call_expr(expr
->args
, bound_info
->param
);
427 if (!get_implied_value(arg
, &offset
))
429 if (offset
>= bound_info
->size
)
430 sm_msg("error: buffer overflow calling %s. param %d. %lld >= %d",
431 fn
, bound_info
->param
, offset
, bound_info
->size
);
434 static void register_array_funcs(void)
438 struct bound
*bound_info
;
440 token
= get_tokens_file("kernel.array_bounds");
443 if (token_type(token
) != TOKEN_STREAMBEGIN
)
446 while (token_type(token
) != TOKEN_STREAMEND
) {
447 bound_info
= malloc(sizeof(*bound_info
));
448 if (token_type(token
) != TOKEN_IDENT
)
450 func
= show_ident(token
->ident
);
452 if (token_type(token
) != TOKEN_NUMBER
)
454 bound_info
->param
= atoi(token
->number
);
456 if (token_type(token
) != TOKEN_NUMBER
)
458 bound_info
->size
= atoi(token
->number
);
459 add_function_hook(func
, &match_array_func
, bound_info
);
465 void check_overflow(int id
)
468 add_hook(&match_function_def
, FUNC_DEF_HOOK
);
469 add_hook(&array_check
, OP_HOOK
);
470 add_hook(&match_string_assignment
, ASSIGNMENT_HOOK
);
471 add_hook(&match_array_assignment
, ASSIGNMENT_HOOK
);
472 add_hook(&match_condition
, CONDITION_HOOK
);
473 add_function_assign_hook("malloc", &match_malloc
, NULL
);
474 add_function_hook("strcpy", &match_strcpy
, NULL
);
475 add_function_hook("strncpy", &match_limitted
, (void *)2);
476 if (option_project
== PROJ_KERNEL
) {
477 add_function_assign_hook("kmalloc", &match_malloc
, NULL
);
478 add_function_assign_hook("kzalloc", &match_malloc
, NULL
);
479 add_function_assign_hook("vmalloc", &match_malloc
, NULL
);
480 add_function_hook("copy_to_user", &match_limitted
, (void *)2);
481 add_function_hook("copy_from_user", &match_limitted
, (void *)2);
483 register_array_funcs();
486 void register_check_overflow_again(int id
)