extra: set hard max if a function is called with a single value
[smatch.git] / check_index_overflow.c
bloba473a4a997afd0fef4064bed68b5f83f0eab33bb
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 (!is_user_data(expr))
69 return 0;
70 if (!get_user_rl(expr, &rl))
71 return 0;
72 *sval = rl_max(rl);
73 return 1;
76 static int common_false_positives(struct expression *array, char *name, sval_t max)
78 if (!name)
79 return 0;
81 /* Smatch can't figure out glibc's strcmp __strcmp_cg()
82 * so it prints an error every time you compare to a string
83 * literal array with 4 or less chars.
85 if (strcmp(name, "__s1") == 0 || strcmp(name, "__s2") == 0)
86 return 1;
88 /* Ugh... People are saying that Smatch still barfs on glibc strcmp()
89 * functions.
91 if (array && array->type == EXPR_STRING) {
92 char *macro;
94 if (max.value == array->string->length)
95 return 1;
97 macro = get_macro_name(array->pos);
98 if (macro &&
99 (strcmp(macro, "strcmp") == 0 ||
100 strcmp(macro, "strncmp") == 0))
101 return 1;
105 * passing WORK_CPU_UNBOUND is idiomatic but Smatch doesn't understand
106 * how it's used so it causes a bunch of false positives.
108 if (option_project == PROJ_KERNEL &&
109 strcmp(name, "__per_cpu_offset") == 0)
110 return 1;
111 return 0;
114 static void array_check(struct expression *expr)
116 struct expression *array_expr;
117 const char *level = "error";
118 int array_size;
119 struct expression *offset;
120 sval_t max;
121 char *name;
123 expr = strip_expr(expr);
124 if (!is_array(expr))
125 return;
127 array_expr = get_array_base(expr);
128 array_size = get_array_size(array_expr);
129 if (!array_size || array_size == 1)
130 return;
132 offset = get_array_offset(expr);
133 if (!get_the_max(offset, &max))
134 return;
135 if (array_size > max.value)
136 return;
137 if (getting_address())
138 level = "warn";
140 if (definitely_just_used_as_limiter(array_expr, offset))
141 return;
143 array_expr = strip_expr(array_expr);
144 name = expr_to_str(array_expr);
145 if (!common_false_positives(array_expr, name, max)) {
146 sm_msg("%s: buffer overflow '%s' %d <= %s",
147 level, name, array_size, sval_to_str(max));
149 free_string(name);
152 void check_index_overflow(int id)
154 add_hook(&array_check, OP_HOOK);