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
21 #include "smatch_slist.h"
22 #include "smatch_extra.h"
24 static int definitely_just_used_as_limiter(struct expression
*array
, struct expression
*offset
)
27 struct expression
*tmp
;
31 if (!get_implied_value(offset
, &sval
))
33 if (get_array_size(array
) != sval
.value
)
36 FOR_EACH_PTR_REVERSE(big_expression_stack
, tmp
) {
41 if (tmp
->type
== EXPR_PREOP
&& tmp
->op
== '(')
43 if (tmp
->op
== '.' && !dot_ops
++)
45 if (step
== 1 && tmp
->op
== '&') {
49 if (step
== 2 && tmp
->type
== EXPR_COMPARE
)
51 if (step
== 2 && tmp
->type
== EXPR_ASSIGNMENT
)
54 } END_FOR_EACH_PTR_REVERSE(tmp
);
58 static int get_the_max(struct expression
*expr
, sval_t
*sval
)
60 struct range_list
*rl
;
62 if (get_hard_max(expr
, sval
))
66 if (get_fuzzy_max(expr
, sval
))
68 if (!is_user_data(expr
))
70 if (!get_user_rl(expr
, &rl
))
76 static int common_false_positives(struct expression
*array
, char *name
, sval_t max
)
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)
88 /* Ugh... People are saying that Smatch still barfs on glibc strcmp()
91 if (array
&& array
->type
== EXPR_STRING
) {
94 if (max
.value
== array
->string
->length
)
97 macro
= get_macro_name(array
->pos
);
99 (strcmp(macro
, "strcmp") == 0 ||
100 strcmp(macro
, "strncmp") == 0))
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)
114 static void array_check(struct expression
*expr
)
116 struct expression
*array_expr
;
117 const char *level
= "error";
119 struct expression
*offset
;
123 expr
= strip_expr(expr
);
127 array_expr
= get_array_base(expr
);
128 array_size
= get_array_size(array_expr
);
129 if (!array_size
|| array_size
== 1)
132 offset
= get_array_offset(expr
);
133 if (!get_the_max(offset
, &max
))
135 if (array_size
> max
.value
)
137 if (getting_address())
140 if (definitely_just_used_as_limiter(array_expr
, offset
))
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
));
152 void check_index_overflow(int id
)
154 add_hook(&array_check
, OP_HOOK
);