sval: fix a signedness bug in check_signed.c
[smatch.git] / check_signed.c
blob6a2c6ddefa666408746a60e668cac3a7c0ccdd6d
1 /*
2 * sparse/check_signed.c
4 * Copyright (C) 2009 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
11 * Check for things which are signed but probably should be unsigned.
13 * Hm... It seems like at this point in the processing, sparse makes all
14 * bitfields unsigned. Which is logical but not what GCC does.
18 #include "smatch.h"
20 static int my_id;
22 #define VAR_ON_RIGHT 0
23 #define VAR_ON_LEFT 1
25 static void match_assign(struct expression *expr)
27 struct symbol *sym;
28 sval_t sval;
29 sval_t max;
30 sval_t min;
31 char *name;
33 if (expr->op == SPECIAL_AND_ASSIGN || expr->op == SPECIAL_OR_ASSIGN)
34 return;
36 sym = get_type(expr->left);
37 if (!sym) {
38 //sm_msg("could not get type");
39 return;
41 if (sym->bit_size >= 32) /* max_val limits this */
42 return;
43 if (!get_implied_value_sval(expr->right, &sval))
44 return;
45 max = sval_type_max(sym);
46 if (sval_cmp(max, sval) < 0 && !(sval.value < 256 && max.value == 127)) {
47 name = get_variable_from_expr_complex(expr->left, NULL);
48 sm_msg("warn: value %s can't fit into %s '%s'",
49 sval_to_str(sval), sval_to_str(max), name);
50 free_string(name);
52 min = sval_type_min(sym);
53 if (sval_cmp(min, sval) > 0) {
54 if (min.value == 0 && sval.value == -1) /* assigning -1 to unsigned variables is idiomatic */
55 return;
56 if (expr->right->type == EXPR_PREOP && expr->right->op == '~')
57 return;
58 if (expr->op == SPECIAL_SUB_ASSIGN || expr->op == SPECIAL_ADD_ASSIGN)
59 return;
60 name = get_variable_from_expr_complex(expr->left, NULL);
61 if (min.value == 0) {
62 sm_msg("warn: assigning %s to unsigned variable '%s'",
63 sval_to_str(sval), name);
64 } else {
65 sm_msg("warn: value %s can't fit into %s '%s'",
66 sval_to_str(sval), sval_to_str(min), name);
68 free_string(name);
72 static const char *get_tf(sval_t variable, sval_t known, int var_pos, int op)
74 if (op == SPECIAL_EQUAL)
75 return "false";
76 if (op == SPECIAL_NOTEQUAL)
77 return "true";
78 if (var_pos == VAR_ON_LEFT) {
79 if (sval_cmp(variable, known) > 0 && (op == '<' || op == SPECIAL_LTE))
80 return "false";
81 if (sval_cmp(variable, known) > 0 && (op == '>' || op == SPECIAL_GTE))
82 return "true";
83 if (sval_cmp(variable, known) < 0 && (op == '<' || op == SPECIAL_LTE))
84 return "true";
85 if (sval_cmp(variable, known) < 0 && (op == '>' || op == SPECIAL_GTE))
86 return "false";
88 if (var_pos == VAR_ON_RIGHT) {
89 if (sval_cmp(known, variable) > 0 && (op == '<' || op == SPECIAL_LTE))
90 return "false";
91 if (sval_cmp(known, variable) > 0 && (op == '>' || op == SPECIAL_GTE))
92 return "true";
93 if (sval_cmp(known, variable) < 0 && (op == '<' || op == SPECIAL_LTE))
94 return "true";
95 if (sval_cmp(known, variable) < 0 && (op == '>' || op == SPECIAL_GTE))
96 return "false";
98 return "the same";
101 static int compare_against_macro(int lr, struct expression *expr)
103 struct expression *known = expr->left;
105 if (lr == VAR_ON_LEFT)
106 known = expr->right;
108 return !!get_macro_name(known->pos);
111 static int cap_both_size(int lr, struct expression *expr)
114 struct expression *var = expr->left;
115 struct expression *tmp;
116 char *name1 = NULL;
117 char *name2 = NULL;
118 int ret = 0;
119 int i;
121 /* screw it. I am writing this to mark yoda code as buggy.
122 * Valid comparisons between an unsigned and zero are:
123 * 1) inside a macro.
124 * 2) foo < LOWER_BOUND where LOWER_BOUND is a macro.
125 * 3) foo < 0 || foo > X in exactly this format. No Yoda.
128 if (lr != VAR_ON_LEFT)
129 return 0;
130 if (expr->op != '<' && expr->op != SPECIAL_UNSIGNED_LT)
131 return 0;
133 i = 0;
134 FOR_EACH_PTR_REVERSE(big_expression_stack, tmp) {
135 if (!i++)
136 continue;
137 if (tmp->op == SPECIAL_LOGICAL_OR) {
138 struct expression *right = strip_expr(tmp->right);
140 if (right->op != '>' &&
141 right->op != SPECIAL_UNSIGNED_GT &&
142 right->op != SPECIAL_GTE &&
143 right->op != SPECIAL_UNSIGNED_GTE)
144 return 0;
146 name1 = get_variable_from_expr_complex(var, NULL);
147 if (!name1)
148 goto free;
150 name2 = get_variable_from_expr_complex(right->left, NULL);
151 if (!name2)
152 goto free;
153 if (!strcmp(name1, name2))
154 ret = 1;
155 goto free;
158 return 0;
159 } END_FOR_EACH_PTR_REVERSE(tmp);
161 free:
162 free_string(name1);
163 free_string(name2);
164 return ret;
167 static void match_condition(struct expression *expr)
169 struct expression *var = NULL;
170 struct symbol *var_type = NULL;
171 struct symbol *known_type = NULL;
172 sval_t known;
173 sval_t max;
174 sval_t min;
175 int lr;
176 char *name;
178 if (expr->type != EXPR_COMPARE)
179 return;
181 if (get_value_sval(expr->left, &known)) {
182 if (get_value_sval(expr->right, &max))
183 return; /* both sides known */
184 lr = VAR_ON_RIGHT;
185 var = expr->right;
186 known_type = get_type(expr->left);
187 } else if (get_value_sval(expr->right, &known)) {
188 lr = VAR_ON_LEFT;
189 var = expr->left;
190 known_type = get_type(expr->right);
191 } else {
192 return;
195 var_type = get_type(var);
196 if (!var_type)
197 return;
198 if (var_type->bit_size >= 32 && !option_spammy)
199 return;
201 name = get_variable_from_expr_complex(var, NULL);
203 if (expr->op == SPECIAL_EQUAL || expr->op == SPECIAL_NOTEQUAL) {
204 sval_t sval_min, sval_max;
206 sval_min = sval_type_min(var_type);
207 sval_max = sval_type_max(var_type);
209 if (sval_cmp(sval_min, known) > 0 || sval_cmp(sval_max, known) < 0)
210 sm_msg("error: %s is never equal to %s (wrong type %s - %s).",
211 name, sval_to_str(known), sval_to_str(sval_min), sval_to_str(sval_max));
212 goto free;
215 max = sval_type_max(var_type);
216 min = sval_type_min(var_type);
218 if (sval_cmp(max, known) < 0) {
219 const char *tf = get_tf(max, known, lr, expr->op);
221 sm_msg("warn: %s is more than %s (max '%s' can be) so this is always %s.",
222 sval_to_str(known), sval_to_str(max), name, tf);
225 if (known.value == 0 && type_unsigned(var_type)) {
226 if ((lr && expr->op == '<') ||
227 (lr && expr->op == SPECIAL_UNSIGNED_LT) ||
228 (!lr && expr->op == '>') ||
229 (!lr && expr->op == SPECIAL_UNSIGNED_GT)) {
230 if (!compare_against_macro(lr, expr) && !cap_both_size(lr, expr)) {
231 sm_msg("warn: unsigned '%s' is never less than zero.", name);
232 goto free;
237 if (type_unsigned(var_type) && known_type && !type_unsigned(known_type) && known.value < 0) {
238 sm_msg("warn: unsigned '%s' is never less than zero %s.", name, sval_to_str(known));
239 goto free;
242 if (sval_signed(min) && sval_signed(known) && sval_cmp(min, known) > 0) {
243 const char *tf = get_tf(min, known, lr, expr->op);
245 sm_msg("warn: %s is less than %s (min '%s' can be) so this is always %s.",
246 sval_to_str(known), sval_to_str(min), name, tf);
248 free:
249 free_string(name);
252 void check_signed(int id)
254 my_id = id;
256 add_hook(&match_assign, ASSIGNMENT_HOOK);
257 add_hook(&match_condition, CONDITION_HOOK);