check_signed: change some error: messages to warn:
[smatch.git] / check_signed.c
blob65e649516b17a8e2ff17a36f95304a4c63b1fbe0
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 RIGHT 0
23 #define LEFT 1
25 static unsigned long long max_size(struct symbol *base_type)
28 I wanted to say:
30 unsigned long long ret = 0xffffffffffffffff;
32 But gcc complained that was too large. What am I doing wrong?
33 Oh well. I expect most of the problems are with smaller
34 values anyway
37 unsigned long long ret = 0xffffffff;
38 int bits;
40 bits = base_type->bit_size;
41 if (base_type->ctype.modifiers & MOD_SIGNED)
42 bits--;
43 ret >>= (32 - bits);
44 return ret;
47 static int is_unsigned(struct symbol *base_type)
49 if (base_type->ctype.modifiers & MOD_UNSIGNED)
50 return 1;
51 return 0;
54 static void match_assign(struct expression *expr)
56 struct symbol *sym;
57 long long val;
58 long long max;
59 char *name;
61 sym = get_type(expr->left);
62 if (!sym) {
63 //sm_msg("could not get type");
64 return;
66 if (sym->bit_size >= 32) /* max_val limits this */
67 return;
68 if (!get_implied_value(expr->right, &val))
69 return;
70 max = max_size(sym);
71 if (max && max < val) {
72 name = get_variable_from_expr_complex(expr->left, NULL);
73 sm_msg("warn: value %lld can't fit into %lld '%s'", val, max, name);
74 free_string(name);
78 static void match_condition(struct expression *expr)
80 long long known;
81 struct expression *var = NULL;
82 struct symbol *type = NULL;
83 long long max;
84 int lr;
85 char *name;
87 if (expr->type != EXPR_COMPARE)
88 return;
90 if (get_value(expr->left, &known)) {
91 lr = RIGHT;
92 var = expr->right;
93 } else if (get_value(expr->right, &known)) {
94 lr = LEFT;
95 var = expr->left;
96 } else {
97 return;
100 type = get_type(var);
101 if (!type || type->bit_size >= 32)
102 return;
104 max = max_size(type);
105 if (!max)
106 return;
108 name = get_variable_from_expr_complex(var, NULL);
110 if (known < 0) {
111 if (is_unsigned(type))
112 sm_msg("error: comparing '%s' to negative", name);
113 goto free;
116 if (known == 0) {
117 if (!is_unsigned(type))
118 goto free;
119 if (lr == LEFT) {
120 if (expr->op == '<')
121 sm_msg("error: unsigned '%s' cannot be less than 0", name);
122 if (expr->op == SPECIAL_LTE)
123 sm_msg("warn: unsigned '%s' cannot be less than 0", name);
125 if (lr == RIGHT) {
126 if (expr->op == '>')
127 sm_msg("error: unsigned '%s' cannot be less than 0", name);
128 if (expr->op == SPECIAL_GTE)
129 sm_msg("warn: unsigned '%s' cannot be less than 0", name);
131 goto free;
134 if (max < known) {
135 const char *tf = "the same";
137 if (expr->op == SPECIAL_EQUAL)
138 tf = "false";
139 if (expr->op == SPECIAL_NOTEQUAL)
140 tf = "true";
141 if (lr == LEFT && (expr->op == '<' || expr->op == SPECIAL_LTE))
142 tf = "true";
143 if (lr == RIGHT && (expr->op == '>' || expr->op == SPECIAL_GTE))
144 tf = "false";
145 sm_msg("warn: %lld is higher than %lld (max '%s' can be) so this is always %s.",
146 known, max, name, tf);
148 free:
149 free_string(name);
152 void check_signed(int id)
154 my_id = id;
156 add_hook(&match_assign, ASSIGNMENT_HOOK);
157 add_hook(&match_condition, CONDITION_HOOK);