type_max(): handle unsigned long long. (sort of)
[smatch.git] / check_signed.c
bloba3858e95c8f6d862c6307e2b6e50f1f829f92610
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 long long val;
29 long long max;
30 long long min;
31 char *name;
33 sym = get_type(expr->left);
34 if (!sym) {
35 //sm_msg("could not get type");
36 return;
38 if (sym->bit_size >= 32) /* max_val limits this */
39 return;
40 if (!get_implied_value(expr->right, &val))
41 return;
42 max = type_max(sym);
43 if (max < val) {
44 name = get_variable_from_expr_complex(expr->left, NULL);
45 sm_msg("warn: value %lld can't fit into %lld '%s'", val, max, name);
46 free_string(name);
48 min = type_min(sym);
49 if (min > val) {
50 if (min == 0 && val == -1) /* assigning -1 to unsigned variables is idiomatic */
51 return;
52 name = get_variable_from_expr_complex(expr->left, NULL);
53 if (min == 0)
54 sm_msg("warn: assigning %lld to unsigned variable '%s'", val, name);
55 else
56 sm_msg("warn: value %lld can't fit into %lld '%s'", val, min, name);
57 free_string(name);
62 static const char *get_tf(long long variable, long long known, int var_pos, int op)
64 if (op == SPECIAL_EQUAL)
65 return "false";
66 if (op == SPECIAL_NOTEQUAL)
67 return "true";
68 if (var_pos == VAR_ON_LEFT) {
69 if (variable > known && (op == '<' || op == SPECIAL_LTE))
70 return "false";
71 if (variable > known && (op == '>' || op == SPECIAL_GTE))
72 return "true";
73 if (variable < known && (op == '<' || op == SPECIAL_LTE))
74 return "true";
75 if (variable < known && (op == '>' || op == SPECIAL_GTE))
76 return "false";
78 if (var_pos == VAR_ON_RIGHT) {
79 if (known > variable && (op == '<' || op == SPECIAL_LTE))
80 return "false";
81 if (known > variable && (op == '>' || op == SPECIAL_GTE))
82 return "true";
83 if (known < variable && (op == '<' || op == SPECIAL_LTE))
84 return "true";
85 if (known < variable && (op == '>' || op == SPECIAL_GTE))
86 return "false";
88 return "the same";
91 static void match_condition(struct expression *expr)
93 long long known;
94 struct expression *var = NULL;
95 struct symbol *type = NULL;
96 long long max;
97 long long min;
98 int lr;
99 char *name;
101 if (expr->type != EXPR_COMPARE)
102 return;
104 if (get_value(expr->left, &known)) {
105 lr = VAR_ON_RIGHT;
106 var = expr->right;
107 } else if (get_value(expr->right, &known)) {
108 lr = VAR_ON_LEFT;
109 var = expr->left;
110 } else {
111 return;
114 type = get_type(var);
115 if (!type)
116 return;
118 max = type_max(type);
119 min = type_min(type);
121 name = get_variable_from_expr_complex(var, NULL);
123 if (known < 0 && type_unsigned(type)) {
124 sm_msg("error: comparing unsigned '%s' to negative", name);
125 goto free;
128 if (known == 0) {
129 if (!type_unsigned(type))
130 goto free;
131 if (lr == VAR_ON_LEFT) {
132 if (expr->op == '<')
133 sm_msg("error: unsigned '%s' cannot be less than 0", name);
134 if (expr->op == SPECIAL_LTE)
135 sm_msg("warn: unsigned '%s' cannot be less than 0", name);
137 if (lr == VAR_ON_RIGHT) {
138 if (expr->op == '>')
139 sm_msg("error: unsigned '%s' cannot be less than 0", name);
140 if (expr->op == SPECIAL_GTE)
141 sm_msg("warn: unsigned '%s' cannot be less than 0", name);
143 goto free;
146 if (max < known) {
147 const char *tf = get_tf(max, known, lr, expr->op);
149 sm_msg("warn: %lld is more than %lld (max '%s' can be) so this is always %s.",
150 known, max, name, tf);
153 if (min > known) {
154 const char *tf = get_tf(max, known, lr, expr->op);
156 sm_msg("warn: %lld is less than %lld (min '%s' can be) so this is always %s.",
157 known, min, name, tf);
159 free:
160 free_string(name);
163 void check_signed(int id)
165 my_id = id;
167 add_hook(&match_assign, ASSIGNMENT_HOOK);
168 add_hook(&match_condition, CONDITION_HOOK);