debug: add __smatch_state_count()
[smatch.git] / check_index_overflow.c
blobc72c405b2f06abf5ef20259be97d79b1789744e9
1 /*
2 * Copyright (C) 2010 Dan Carpenter.
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
18 #include <stdlib.h>
19 #include "parse.h"
20 #include "smatch.h"
21 #include "smatch_slist.h"
22 #include "smatch_extra.h"
24 static int definitely_just_used_as_limiter(struct expression *array, struct expression *offset)
26 sval_t sval;
27 struct expression *tmp;
28 int step = 0;
29 int dot_ops = 0;
31 if (!get_implied_value(offset, &sval))
32 return 0;
33 if (get_array_size(array) != sval.value)
34 return 0;
36 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
37 if (step == 0) {
38 step = 1;
39 continue;
41 if (tmp->type == EXPR_PREOP && tmp->op == '(')
42 continue;
43 if (tmp->op == '.' && !dot_ops++)
44 continue;
45 if (step == 1 && tmp->op == '&') {
46 step = 2;
47 continue;
49 if (step == 2 && tmp->type == EXPR_COMPARE)
50 return 1;
51 if (step == 2 && tmp->type == EXPR_ASSIGNMENT)
52 return 1;
53 return 0;
54 } END_FOR_EACH_PTR_REVERSE(tmp);
55 return 0;
58 static int get_the_max(struct expression *expr, sval_t *sval)
60 struct range_list *rl;
62 if (get_hard_max(expr, sval))
63 return 1;
64 if (!option_spammy)
65 return 0;
66 if (get_fuzzy_max(expr, sval))
67 return 1;
68 if (!get_user_rl(expr, &rl))
69 return 0;
70 *sval = rl_max(rl);
71 return 1;
74 static int common_false_positives(struct expression *array, char *name, sval_t max)
76 if (!name)
77 return 0;
79 /* Smatch can't figure out glibc's strcmp __strcmp_cg()
80 * so it prints an error every time you compare to a string
81 * literal array with 4 or less chars.
83 if (strcmp(name, "__s1") == 0 || strcmp(name, "__s2") == 0)
84 return 1;
86 /* Ugh... People are saying that Smatch still barfs on glibc strcmp()
87 * functions.
89 if (array) {
90 char *macro;
92 /* why is this again??? */
93 if (array->type == EXPR_STRING &&
94 max.value == array->string->length)
95 return 1;
97 macro = get_macro_name(array->pos);
98 if (macro && max.uvalue < 4 &&
99 (strcmp(macro, "strcmp") == 0 ||
100 strcmp(macro, "strncmp") == 0 ||
101 strcmp(macro, "streq") == 0 ||
102 strcmp(macro, "strneq") == 0 ||
103 strcmp(macro, "strsep") == 0))
104 return 1;
108 * passing WORK_CPU_UNBOUND is idiomatic but Smatch doesn't understand
109 * how it's used so it causes a bunch of false positives.
111 if (option_project == PROJ_KERNEL &&
112 strcmp(name, "__per_cpu_offset") == 0)
113 return 1;
114 return 0;
117 static void array_check(struct expression *expr)
119 struct expression *array_expr;
120 int array_size;
121 struct expression *offset;
122 sval_t max;
123 char *name;
125 expr = strip_expr(expr);
126 if (!is_array(expr))
127 return;
129 if (is_impossible_path())
130 return;
131 array_expr = get_array_base(expr);
132 array_size = get_array_size(array_expr);
133 if (!array_size || array_size == 1)
134 return;
136 offset = get_array_offset(expr);
137 if (!get_the_max(offset, &max))
138 return;
139 if (array_size > max.value)
140 return;
142 if (definitely_just_used_as_limiter(array_expr, offset))
143 return;
145 array_expr = strip_expr(array_expr);
146 name = expr_to_str(array_expr);
147 if (common_false_positives(array_expr, name, max))
148 goto free;
150 sm_msg("error: buffer overflow '%s' %d <= %s", name, array_size, sval_to_str(max));
152 free:
153 free_string(name);
156 void check_index_overflow(int id)
158 add_hook(&array_check, OP_HOOK);