Fix OpenBSD compile
[smatch.git] / check_signed.c
blob9e7c57ec55d598a3dde7f09cdf6d52b72d8d2358
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 int is_unsigned(struct symbol *base_type)
27 if (base_type->ctype.modifiers & MOD_UNSIGNED)
28 return 1;
29 return 0;
32 static void match_assign(struct expression *expr)
34 struct symbol *sym;
35 long long val;
36 long long max;
37 long long min;
38 char *name;
40 sym = get_type(expr->left);
41 if (!sym) {
42 //sm_msg("could not get type");
43 return;
45 if (sym->bit_size >= 32) /* max_val limits this */
46 return;
47 if (!get_implied_value(expr->right, &val))
48 return;
49 max = type_max(sym);
50 if (max && max < val) {
51 name = get_variable_from_expr_complex(expr->left, NULL);
52 sm_msg("warn: value %lld can't fit into %lld '%s'", val, max, name);
53 free_string(name);
55 min = type_min(sym);
56 if (min > val) {
57 name = get_variable_from_expr_complex(expr->left, NULL);
58 sm_msg("warn: value %lld can't fit into %lld '%s'", val, min, name);
59 free_string(name);
64 static const char *get_tf(long long variable, long long known, int var_pos, char op)
66 if (op == SPECIAL_EQUAL)
67 return "false";
68 if (op == SPECIAL_NOTEQUAL)
69 return "true";
70 if (var_pos == VAR_ON_LEFT) {
71 if (variable > known && (op == '<' || op == SPECIAL_LTE))
72 return "false";
73 if (variable > known && (op == '>' || op == SPECIAL_GTE))
74 return "true";
75 if (variable < known && (op == '<' || op == SPECIAL_LTE))
76 return "true";
77 if (variable < known && (op == '>' || op == SPECIAL_GTE))
78 return "false";
80 if (var_pos == VAR_ON_RIGHT) {
81 if (known > variable && (op == '<' || op == SPECIAL_LTE))
82 return "false";
83 if (known > variable && (op == '>' || op == SPECIAL_GTE))
84 return "true";
85 if (known < variable && (op == '<' || op == SPECIAL_LTE))
86 return "true";
87 if (known < variable && (op == '>' || op == SPECIAL_GTE))
88 return "false";
90 return "the same";
93 static void match_condition(struct expression *expr)
95 long long known;
96 struct expression *var = NULL;
97 struct symbol *type = NULL;
98 long long max;
99 long long min;
100 int lr;
101 char *name;
103 if (expr->type != EXPR_COMPARE)
104 return;
106 if (get_value(expr->left, &known)) {
107 lr = VAR_ON_RIGHT;
108 var = expr->right;
109 } else if (get_value(expr->right, &known)) {
110 lr = VAR_ON_LEFT;
111 var = expr->left;
112 } else {
113 return;
116 type = get_type(var);
117 if (!type || type->bit_size >= 32)
118 return;
120 max = type_max(type);
121 if (!max)
122 return;
123 min = type_min(type);
125 name = get_variable_from_expr_complex(var, NULL);
127 if (known < 0 && is_unsigned(type)) {
128 sm_msg("error: comparing unsigned '%s' to negative", name);
129 goto free;
132 if (known == 0) {
133 if (!is_unsigned(type))
134 goto free;
135 if (lr == VAR_ON_LEFT) {
136 if (expr->op == '<')
137 sm_msg("error: unsigned '%s' cannot be less than 0", name);
138 if (expr->op == SPECIAL_LTE)
139 sm_msg("warn: unsigned '%s' cannot be less than 0", name);
141 if (lr == VAR_ON_RIGHT) {
142 if (expr->op == '>')
143 sm_msg("error: unsigned '%s' cannot be less than 0", name);
144 if (expr->op == SPECIAL_GTE)
145 sm_msg("warn: unsigned '%s' cannot be less than 0", name);
147 goto free;
150 if (max < known) {
151 const char *tf = get_tf(max, known, lr, expr->op);
153 sm_msg("warn: %lld is more than %lld (max '%s' can be) so this is always %s.",
154 known, max, name, tf);
157 if (min > known) {
158 const char *tf = get_tf(max, known, lr, expr->op);
160 sm_msg("warn: %lld is less than %lld (min '%s' can be) so this is always %s.",
161 known, min, name, tf);
163 free:
164 free_string(name);
167 void check_signed(int id)
169 my_id = id;
171 add_hook(&match_assign, ASSIGNMENT_HOOK);
172 add_hook(&match_condition, CONDITION_HOOK);