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 if (get_hard_max(expr
, sval
))
64 if (get_fuzzy_max(expr
, sval
))
66 if (is_user_data(expr
))
67 return get_absolute_max(expr
, sval
);
71 static int common_false_positives(struct expression
*array
, char *name
, sval_t max
)
76 /* Smatch can't figure out glibc's strcmp __strcmp_cg()
77 * so it prints an error every time you compare to a string
78 * literal array with 4 or less chars.
80 if (strcmp(name
, "__s1") == 0 || strcmp(name
, "__s2") == 0)
83 /* Ugh... People are saying that Smatch still barfs on glibc strcmp()
86 if (array
&& array
->type
== EXPR_STRING
) {
89 if (max
.value
== array
->string
->length
)
92 macro
= get_macro_name(array
->pos
);
94 (strcmp(macro
, "strcmp") == 0 ||
95 strcmp(macro
, "strncmp") == 0))
100 * passing WORK_CPU_UNBOUND is idiomatic but Smatch doesn't understand
101 * how it's used so it causes a bunch of false positives.
103 if (option_project
== PROJ_KERNEL
&&
104 strcmp(name
, "__per_cpu_offset") == 0)
109 static void array_check(struct expression
*expr
)
111 struct expression
*array_expr
;
112 const char *level
= "error";
114 struct expression
*offset
;
118 expr
= strip_expr(expr
);
122 array_expr
= get_array_base(expr
);
123 array_size
= get_array_size(array_expr
);
124 if (!array_size
|| array_size
== 1)
127 offset
= get_array_offset(expr
);
128 if (!get_the_max(offset
, &max
))
130 if (array_size
> max
.value
)
132 if (getting_address())
135 if (definitely_just_used_as_limiter(array_expr
, offset
))
138 array_expr
= strip_expr(array_expr
);
139 name
= expr_to_str(array_expr
);
140 if (!common_false_positives(array_expr
, name
, max
)) {
141 sm_msg("%s: buffer overflow '%s' %d <= %s",
142 level
, name
, array_size
, sval_to_str(max
));
147 void check_index_overflow(int id
)
149 add_hook(&array_check
, OP_HOOK
);