2 * Copyright (C) 2012 Oracle.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
19 * The point here is to store that a buffer has x bytes even if we don't know
25 #include "smatch_extra.h"
26 #include "smatch_slist.h"
32 * There is a bunch of code which does this:
37 * So if "size" is non-zero then the size of "foo" is size. But really it's
38 * also true if size is zero. It's just better to assume to not trample over
39 * the data that we have by merging &undefined states.
42 static struct smatch_state
*unmatched_state(struct sm_state
*sm
)
47 static struct smatch_state
*merge_links(struct smatch_state
*s1
, struct smatch_state
*s2
)
49 struct expression
*expr1
, *expr2
;
54 if (expr1
&& expr2
&& expr_equiv(expr1
, expr2
))
59 static void match_link_modify(struct sm_state
*sm
, struct expression
*mod_expr
)
61 struct expression
*expr
;
64 expr
= sm
->state
->data
;
66 set_state_expr(size_id
, expr
, &undefined
);
67 set_state(link_id
, sm
->name
, sm
->sym
, &undefined
);
71 FOR_EACH_PTR(sm
->possible
, tmp
) {
72 expr
= tmp
->state
->data
;
74 set_state_expr(size_id
, expr
, &undefined
);
75 } END_FOR_EACH_PTR(tmp
);
76 set_state(link_id
, sm
->name
, sm
->sym
, &undefined
);
79 static const char *limit_map
[] = {
87 int state_to_limit(struct smatch_state
*state
)
91 if (!state
|| !state
->data
)
94 for (i
= 0; i
< ARRAY_SIZE(limit_map
); i
++) {
95 if (strncmp(state
->name
, limit_map
[i
], strlen(limit_map
[i
])) == 0)
96 return i
+ BYTE_COUNT
;
102 const char *limit_type_str(unsigned int limit_type
)
104 if (limit_type
- BYTE_COUNT
>= ARRAY_SIZE(limit_map
)) {
105 sm_msg("internal: wrong size type %u", limit_type
);
109 return limit_map
[limit_type
- BYTE_COUNT
];
112 static struct smatch_state
*alloc_compare_size(int limit_type
, struct expression
*expr
)
114 struct smatch_state
*state
;
118 state
= __alloc_smatch_state(0);
119 expr
= strip_expr(expr
);
120 name
= expr_to_str(expr
);
121 snprintf(buf
, sizeof(buf
), "%s %s", limit_type_str(limit_type
), name
);
122 state
->name
= alloc_sname(buf
);
128 static int bytes_per_element(struct expression
*expr
)
132 type
= get_type(expr
);
136 if (type
->type
!= SYM_PTR
&& type
->type
!= SYM_ARRAY
)
139 type
= get_base_type(type
);
140 return type_bytes(type
);
143 static void db_save_type_links(struct expression
*array
, int type_limit
, struct expression
*size
)
145 const char *array_name
;
147 array_name
= get_data_info_name(array
);
150 sql_insert_data_info(size
, type_limit
, array_name
);
153 static void match_alloc_helper(struct expression
*pointer
, struct expression
*size
)
155 struct expression
*tmp
;
157 int limit_type
= ELEM_COUNT
;
161 pointer
= strip_expr(pointer
);
162 size
= strip_expr(size
);
163 if (!size
|| !pointer
)
166 while ((tmp
= get_assigned_expr(size
))) {
167 size
= strip_expr(tmp
);
172 if (size
->type
== EXPR_BINOP
&& size
->op
== '*') {
173 struct expression
*mult_left
, *mult_right
;
175 mult_left
= strip_expr(size
->left
);
176 mult_right
= strip_expr(size
->right
);
178 if (get_implied_value(mult_left
, &sval
) &&
179 sval
.value
== bytes_per_element(pointer
))
181 else if (get_implied_value(mult_right
, &sval
) &&
182 sval
.value
== bytes_per_element(pointer
))
188 /* Only save links to variables, not fixed sizes */
189 if (get_value(size
, &sval
))
192 if (size
->type
== EXPR_BINOP
&& size
->op
== '+' &&
193 get_value(size
->right
, &sval
) && sval
.value
== 1) {
195 limit_type
= ELEM_LAST
;
198 db_save_type_links(pointer
, limit_type
, size
);
199 sm
= set_state_expr(size_id
, pointer
, alloc_compare_size(limit_type
, size
));
202 set_state_expr(link_id
, size
, alloc_state_expr(pointer
));
205 static void match_alloc(const char *fn
, struct expression
*expr
, void *_size_arg
)
207 int size_arg
= PTR_INT(_size_arg
);
208 struct expression
*pointer
, *call
, *arg
;
210 pointer
= strip_expr(expr
->left
);
211 call
= strip_expr(expr
->right
);
212 arg
= get_argument_from_call_expr(call
->args
, size_arg
);
213 match_alloc_helper(pointer
, arg
);
216 static void match_calloc(const char *fn
, struct expression
*expr
, void *_start_arg
)
218 int start_arg
= PTR_INT(_start_arg
);
219 struct expression
*pointer
, *call
, *arg
;
220 struct sm_state
*tmp
;
221 int limit_type
= ELEM_COUNT
;
224 pointer
= strip_expr(expr
->left
);
225 call
= strip_expr(expr
->right
);
226 arg
= get_argument_from_call_expr(call
->args
, start_arg
);
227 if (get_implied_value(arg
, &sval
) &&
228 sval
.value
== bytes_per_element(pointer
))
229 arg
= get_argument_from_call_expr(call
->args
, start_arg
+ 1);
231 if (arg
->type
== EXPR_BINOP
&& arg
->op
== '+' &&
232 get_value(arg
->right
, &sval
) && sval
.value
== 1) {
234 limit_type
= ELEM_LAST
;
237 db_save_type_links(pointer
, limit_type
, arg
);
238 tmp
= set_state_expr(size_id
, pointer
, alloc_compare_size(limit_type
, arg
));
241 set_state_expr(link_id
, arg
, alloc_state_expr(pointer
));
244 struct expression
*get_size_variable(struct expression
*buf
, int *limit_type
)
246 struct smatch_state
*state
;
248 state
= get_state_expr(size_id
, buf
);
251 *limit_type
= state_to_limit(state
);
255 struct expression
*get_array_variable(struct expression
*size
)
257 struct smatch_state
*state
;
259 state
= get_state_expr(link_id
, size
);
265 static void array_check(struct expression
*expr
)
267 struct expression
*array
;
268 struct expression
*size
;
269 struct expression
*offset
;
270 char *array_str
, *offset_str
;
273 expr
= strip_expr(expr
);
277 array
= get_array_base(expr
);
278 size
= get_size_variable(array
, &limit_type
);
281 if (limit_type
!= ELEM_COUNT
)
283 offset
= get_array_offset(expr
);
284 if (!possible_comparison(size
, SPECIAL_EQUAL
, offset
))
287 array_str
= expr_to_str(array
);
288 offset_str
= expr_to_str(offset
);
289 sm_warning("potentially one past the end of array '%s[%s]'", array_str
, offset_str
);
290 free_string(array_str
);
291 free_string(offset_str
);
299 static int db_limitter_callback(void *_info
, int argc
, char **argv
, char **azColName
)
301 struct db_info
*info
= _info
;
304 * If possible the limitters are tied to the struct they limit. If we
305 * aren't sure which struct they limit then we use them as limitters for
308 if (!info
->name
|| argv
[0][0] == '\0' || strcmp(info
->name
, argv
[0]) == 0)
313 static char *vsl_to_data_info_name(const char *name
, struct var_sym_list
*vsl
)
320 if (ptr_list_size((struct ptr_list
*)vsl
) != 1)
322 vs
= first_ptr_list((struct ptr_list
*)vsl
);
324 type
= get_real_base_type(vs
->sym
);
325 if (!type
|| type
->type
!= SYM_PTR
)
327 type
= get_real_base_type(type
);
328 if (!type
|| type
->type
!= SYM_STRUCT
)
334 while ((name
= strstr(p
, "->")))
337 snprintf(buf
, sizeof(buf
),"(struct %s)->%s", type
->ident
->name
, p
);
338 return alloc_sname(buf
);
341 if (!(vs
->sym
->ctype
.modifiers
& MOD_TOPLEVEL
))
343 if (vs
->sym
->ctype
.modifiers
& MOD_STATIC
)
344 snprintf(buf
, sizeof(buf
),"static %s", name
);
346 snprintf(buf
, sizeof(buf
),"global %s", name
);
347 return alloc_sname(buf
);
350 int db_var_is_array_limit(struct expression
*array
, const char *name
, struct var_sym_list
*vsl
)
353 char *array_name
= get_data_info_name(array
);
354 struct db_info db_info
= {.name
= array_name
,};
356 size_name
= vsl_to_data_info_name(name
, vsl
);
360 run_sql(db_limitter_callback
, &db_info
,
361 "select value from data_info where type = %d and data = '%s';",
362 ARRAY_LEN
, size_name
);
367 int buf_comparison_index_ok(struct expression
*expr
)
369 struct expression
*array
;
370 struct expression
*size
;
371 struct expression
*offset
;
375 array
= get_array_base(expr
);
376 size
= get_size_variable(array
, &limit_type
);
379 offset
= get_array_offset(expr
);
380 comparison
= get_comparison(offset
, size
);
384 if ((limit_type
== ELEM_COUNT
|| limit_type
== ELEM_LAST
) &&
385 (comparison
== '<' || comparison
== SPECIAL_UNSIGNED_LT
))
387 if (limit_type
== ELEM_LAST
&&
388 (comparison
== SPECIAL_LTE
||
389 comparison
== SPECIAL_UNSIGNED_LTE
||
390 comparison
== SPECIAL_EQUAL
))
396 static int known_access_ok_numbers(struct expression
*expr
)
398 struct expression
*array
;
399 struct expression
*offset
;
403 array
= get_array_base(expr
);
404 offset
= get_array_offset(expr
);
406 size
= get_array_size(array
);
410 get_absolute_max(offset
, &max
);
411 if (max
.uvalue
< size
)
416 static void array_check_data_info(struct expression
*expr
)
418 struct expression
*array
;
419 struct expression
*offset
;
420 struct state_list
*slist
;
422 struct compare_data
*comp
;
424 const char *equal_name
= NULL
;
426 expr
= strip_expr(expr
);
430 if (known_access_ok_numbers(expr
))
432 if (buf_comparison_index_ok(expr
))
435 array
= get_array_base(expr
);
436 offset
= get_array_offset(expr
);
437 offset_name
= expr_to_var(offset
);
440 slist
= get_all_possible_equal_comparisons(offset
);
444 FOR_EACH_PTR(slist
, sm
) {
445 comp
= sm
->state
->data
;
446 if (strcmp(comp
->left_var
, offset_name
) == 0) {
447 if (db_var_is_array_limit(array
, comp
->right_var
, comp
->right_vsl
)) {
448 equal_name
= comp
->right_var
;
451 } else if (strcmp(comp
->right_var
, offset_name
) == 0) {
452 if (db_var_is_array_limit(array
, comp
->left_var
, comp
->left_vsl
)) {
453 equal_name
= comp
->left_var
;
457 } END_FOR_EACH_PTR(sm
);
460 char *array_name
= expr_to_str(array
);
462 sm_warning("potential off by one '%s[]' limit '%s'", array_name
, equal_name
);
463 free_string(array_name
);
468 free_string(offset_name
);
471 static void add_allocation_function(const char *func
, void *call_back
, int param
)
473 add_function_assign_hook(func
, call_back
, INT_PTR(param
));
476 static int is_sizeof(struct expression
*expr
)
480 if (expr
->type
== EXPR_SIZEOF
)
482 name
= pos_ident(expr
->pos
);
483 if (name
&& strcmp(name
, "sizeof") == 0)
488 static int match_size_binop(struct expression
*size
, struct expression
*expr
, int *limit_type
)
490 int orig_type
= *limit_type
;
491 struct expression
*left
;
495 if (!expr_equiv(size
, left
))
498 if (expr
->op
== '-' &&
499 get_value(expr
->right
, &sval
) &&
501 orig_type
== ELEM_COUNT
) {
502 *limit_type
= ELEM_LAST
;
506 if (expr
->op
== '+' &&
507 get_value(expr
->right
, &sval
) &&
509 orig_type
== ELEM_LAST
) {
510 *limit_type
= ELEM_COUNT
;
514 if (expr
->op
== '*' &&
515 is_sizeof(expr
->right
) &&
516 orig_type
== ELEM_COUNT
) {
517 *limit_type
= BYTE_COUNT
;
521 if (expr
->op
== '/' &&
522 is_sizeof(expr
->right
) &&
523 orig_type
== BYTE_COUNT
) {
524 *limit_type
= ELEM_COUNT
;
531 static char *buf_size_param_comparison(struct expression
*array
, struct expression_list
*args
, int *limit_type
)
533 struct expression
*tmp
, *arg
;
534 struct expression
*size
;
538 size
= get_size_variable(array
, limit_type
);
542 if (*limit_type
== USED_LAST
)
543 *limit_type
= ELEM_LAST
;
544 if (*limit_type
== USED_COUNT
)
545 *limit_type
= ELEM_COUNT
;
548 FOR_EACH_PTR(args
, tmp
) {
553 if (expr_equiv(arg
, size
) ||
554 (arg
->type
== EXPR_BINOP
&&
555 match_size_binop(size
, arg
, limit_type
))) {
556 snprintf(buf
, sizeof(buf
), "==$%d", i
);
559 } END_FOR_EACH_PTR(tmp
);
564 static void match_call(struct expression
*call
)
566 struct expression
*arg
;
573 FOR_EACH_PTR(call
->args
, arg
) {
575 if (!is_pointer(arg
))
577 compare
= buf_size_param_comparison(arg
, call
->args
, &limit_type
);
580 snprintf(buf
, sizeof(buf
), "%d", limit_type
);
581 sql_insert_caller_info(call
, limit_type
, param
, compare
, buf
);
582 } END_FOR_EACH_PTR(arg
);
585 static int get_param(int param
, char **name
, struct symbol
**sym
)
591 FOR_EACH_PTR(cur_func_sym
->ctype
.base_type
->arguments
, arg
) {
593 * this is a temporary hack to work around a bug (I think in sparse?)
594 * 2.6.37-rc1:fs/reiserfs/journal.o
595 * If there is a function definition without parameter name found
596 * after a function implementation then it causes a crash.
600 if (arg
->ident
->name
< (char *)100)
603 *name
= arg
->ident
->name
;
608 } END_FOR_EACH_PTR(arg
);
613 static void set_param_compare(const char *array_name
, struct symbol
*array_sym
, char *key
, char *value
)
615 struct expression
*array_expr
;
616 struct expression
*size_expr
;
617 struct symbol
*size_sym
;
620 struct sm_state
*tmp
;
623 if (strncmp(key
, "==$", 3) != 0)
625 param
= strtol(key
+ 3, NULL
, 10);
626 if (!get_param(param
, &size_name
, &size_sym
))
628 array_expr
= symbol_expression(array_sym
);
629 size_expr
= symbol_expression(size_sym
);
630 limit_type
= strtol(value
, NULL
, 10);
632 tmp
= set_state_expr(size_id
, array_expr
, alloc_compare_size(limit_type
, size_expr
));
635 set_state_expr(link_id
, size_expr
, alloc_state_expr(array_expr
));
638 static void set_implied(struct expression
*call
, struct expression
*array_expr
, char *key
, char *value
)
640 struct expression
*size_expr
;
641 struct symbol
*size_sym
;
644 struct sm_state
*tmp
;
647 if (strncmp(key
, "==$", 3) != 0)
649 param
= strtol(key
+ 3, NULL
, 10);
650 if (!get_param(param
, &size_name
, &size_sym
))
652 size_expr
= symbol_expression(size_sym
);
654 limit_type
= strtol(value
, NULL
, 10);
655 tmp
= set_state_expr(size_id
, array_expr
, alloc_compare_size(limit_type
, size_expr
));
658 set_state_expr(link_id
, size_expr
, alloc_state_expr(array_expr
));
661 static void munge_start_states(struct statement
*stmt
)
663 struct state_list
*slist
= NULL
;
665 struct sm_state
*poss
;
667 FOR_EACH_MY_SM(size_id
, __get_cur_stree(), sm
) {
668 if (sm
->state
!= &merged
)
671 * screw it. let's just assume that if one caller passes the
672 * size then they all do.
674 FOR_EACH_PTR(sm
->possible
, poss
) {
675 if (poss
->state
!= &merged
&&
676 poss
->state
!= &undefined
) {
677 add_ptr_list(&slist
, poss
);
680 } END_FOR_EACH_PTR(poss
);
681 } END_FOR_EACH_SM(sm
);
683 FOR_EACH_PTR(slist
, sm
) {
684 set_state(size_id
, sm
->name
, sm
->sym
, sm
->state
);
685 } END_FOR_EACH_PTR(sm
);
690 static void set_used(struct expression
*expr
)
692 struct expression
*parent
;
693 struct expression
*array
;
694 struct expression
*offset
;
695 struct sm_state
*tmp
;
698 if (expr
->op
!= SPECIAL_INCREMENT
)
701 limit_type
= USED_LAST
;
702 if (expr
->type
== EXPR_POSTOP
)
703 limit_type
= USED_COUNT
;
705 parent
= expr_get_parent_expr(expr
);
706 if (!parent
|| parent
->type
!= EXPR_BINOP
)
708 parent
= expr_get_parent_expr(parent
);
709 if (!parent
|| !is_array(parent
))
712 array
= get_array_base(parent
);
713 offset
= get_array_offset(parent
);
717 tmp
= set_state_expr(size_id
, array
, alloc_compare_size(limit_type
, offset
->unop
));
720 set_state_expr(link_id
, offset
->unop
, alloc_state_expr(array
));
723 static int match_assign_array(struct expression
*expr
)
729 static int match_assign_size(struct expression
*expr
)
731 struct expression
*right
, *size
, *array
;
732 struct smatch_state
*state
;
733 struct sm_state
*tmp
;
738 if (size
->type
== EXPR_BINOP
)
741 array
= get_array_variable(size
);
744 state
= get_state_expr(size_id
, array
);
745 if (!state
|| !state
->data
)
748 limit_type
= state_to_limit(state
);
752 if (right
->type
== EXPR_BINOP
&& !match_size_binop(size
, right
, &limit_type
))
755 tmp
= set_state_expr(size_id
, array
, alloc_compare_size(limit_type
, expr
->left
));
758 set_state_expr(link_id
, expr
->left
, alloc_state_expr(array
));
762 static void match_assign(struct expression
*expr
)
767 if (match_assign_array(expr
))
769 match_assign_size(expr
);
772 static void match_copy(const char *fn
, struct expression
*expr
, void *unused
)
774 struct expression
*src
, *size
;
775 int src_param
, size_param
;
777 src
= get_argument_from_call_expr(expr
->args
, 1);
778 size
= get_argument_from_call_expr(expr
->args
, 2);
779 src
= strip_expr(src
);
780 size
= strip_expr(size
);
783 if (src
->type
!= EXPR_SYMBOL
|| size
->type
!= EXPR_SYMBOL
)
786 src_param
= get_param_num_from_sym(src
->symbol
);
787 size_param
= get_param_num_from_sym(size
->symbol
);
788 if (src_param
< 0 || size_param
< 0)
791 sql_insert_cache(call_implies
, "'%s', '%s', 0, %d, %d, %d, '==$%d', '%d'",
792 get_base_file(), get_function(), fn_static(),
793 BYTE_COUNT
, src_param
, size_param
, BYTE_COUNT
);
796 void register_buf_comparison(int id
)
802 set_dynamic_states(size_id
);
804 add_unmatched_state_hook(size_id
, &unmatched_state
);
806 add_allocation_function("malloc", &match_alloc
, 0);
807 add_allocation_function("memdup", &match_alloc
, 1);
808 add_allocation_function("realloc", &match_alloc
, 1);
809 if (option_project
== PROJ_KERNEL
) {
810 add_allocation_function("kmalloc", &match_alloc
, 0);
811 add_allocation_function("kzalloc", &match_alloc
, 0);
812 add_allocation_function("vmalloc", &match_alloc
, 0);
813 add_allocation_function("__vmalloc", &match_alloc
, 0);
814 add_allocation_function("sock_kmalloc", &match_alloc
, 1);
815 add_allocation_function("kmemdup", &match_alloc
, 1);
816 add_allocation_function("kmemdup_user", &match_alloc
, 1);
817 add_allocation_function("dma_alloc_attrs", &match_alloc
, 1);
818 add_allocation_function("pci_alloc_consistent", &match_alloc
, 1);
819 add_allocation_function("pci_alloc_coherent", &match_alloc
, 1);
820 add_allocation_function("devm_kmalloc", &match_alloc
, 1);
821 add_allocation_function("devm_kzalloc", &match_alloc
, 1);
822 add_allocation_function("kcalloc", &match_calloc
, 0);
823 add_allocation_function("devm_kcalloc", &match_calloc
, 1);
824 add_allocation_function("kmalloc_array", &match_calloc
, 0);
825 add_allocation_function("krealloc", &match_alloc
, 1);
827 add_function_hook("copy_from_user", &match_copy
, NULL
);
828 add_function_hook("__copy_from_user", &match_copy
, NULL
);
831 add_hook(&array_check
, OP_HOOK
);
832 add_hook(&array_check_data_info
, OP_HOOK
);
833 add_hook(&set_used
, OP_HOOK
);
835 add_hook(&match_call
, FUNCTION_CALL_HOOK
);
836 add_hook(&munge_start_states
, AFTER_DEF_HOOK
);
838 add_hook(&match_assign
, ASSIGNMENT_HOOK
);
840 for (i
= BYTE_COUNT
; i
<= USED_COUNT
; i
++) {
841 select_call_implies_hook(i
, &set_implied
);
842 select_caller_info_hook(set_param_compare
, i
);
843 select_return_implies_hook(i
, &set_implied
);
847 void register_buf_comparison_links(int id
)
850 set_dynamic_states(link_id
);
851 add_merge_hook(link_id
, &merge_links
);
852 add_modification_hook(link_id
, &match_link_modify
);