sval: update check_snprintf.c
[smatch.git] / smatch_sval.c
blob4021ca17544c54dabe27c49c1cf9e0e3f29ad58f
1 /*
2 * smatch/smatch_sval.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
9 * Basically the point of sval is that it can hold both ULLONG_MAX and
10 * LLONG_MIN. If it is an unsigned type then we use sval.uvalue or if it is
11 * signed we use sval.value.
13 * I considered just using one bit to store whether the value was signed vs
14 * unsigned but I think it might help to have the type information so we know
15 * how to do type promotion.
19 #include "smatch.h"
20 #include "smatch_slist.h"
21 #include "smatch_extra.h"
23 __ALLOCATOR(sval_t, "svals", sval);
25 sval_t *sval_alloc(sval_t sval)
27 sval_t *ret;
29 ret = __alloc_sval(0);
30 *ret = sval;
31 return ret;
34 sval_t *sval_alloc_permanent(sval_t sval)
36 sval_t *ret;
38 ret = malloc(sizeof(*ret));
39 *ret = sval;
40 return ret;
43 sval_t sval_blank(struct expression *expr)
45 sval_t ret;
47 ret.type = get_type(expr);
48 if (!ret.type)
49 ret.type = &llong_ctype;
50 ret.value = 123456789;
52 return ret;
55 sval_t sval_from_val(struct expression *expr, long long val)
57 sval_t ret;
59 ret = sval_blank(expr);
60 ret.value = val;
61 ret = sval_cast(ret, expr);
63 return ret;
66 int sval_unsigned(sval_t sval)
68 return type_unsigned(sval.type);
71 int sval_signed(sval_t sval)
73 return !type_unsigned(sval.type);
76 int sval_bits(sval_t sval)
78 if (!sval.type)
79 return 32;
80 return sval.type->bit_size;
84 * Casts the values and then does a compare. Returns -1 if one is smaller, 0 if
85 * they are the same and 1 if two is larger.
87 int sval_cmp(sval_t one, sval_t two)
89 if (one.value < two.value)
90 return -1;
91 if (one.value == two.value)
92 return 0;
93 return 1;
96 int sval_cmp_val(sval_t one, long long val)
98 if (one.value < val)
99 return -1;
100 if (one.value == val)
101 return 0;
102 return 1;
105 sval_t sval_cast(sval_t sval, struct expression *expr)
107 sval_t ret;
109 ret = sval_blank(expr);
110 switch (sval_bits(ret)) {
111 case 8:
112 if (sval_unsigned(ret))
113 ret.value = (long long)(unsigned char)sval.value;
114 else
115 ret.value = (long long)(char)sval.value;
116 break;
117 case 16:
118 if (sval_unsigned(ret))
119 ret.value = (long long)(unsigned short)sval.value;
120 else
121 ret.value = (long long)(short)sval.value;
122 break;
123 case 32:
124 if (sval_unsigned(ret))
125 ret.value = (long long)(unsigned int)sval.value;
126 else
127 ret.value = (long long)(int)sval.value;
128 break;
129 default:
130 ret.value = sval.value;
132 return ret;
136 sval_t sval_preop(sval_t sval, int op)
138 switch (op) {
139 case '!':
140 sval.value = !sval.value;
141 break;
142 case '~':
143 sval.value = ~sval.value;
144 /* fixme: should probably cast this here */
145 break;
146 case '-':
147 sval.value = -sval.value;
148 break;
150 return sval;
153 sval_t sval_binop(sval_t left, int op, sval_t right)
155 sval_t ret;
157 /* fixme: these need to have proper type promotions */
158 ret.type = left.type;
159 switch (op) {
160 case '*':
161 ret.value = left.value * right.value;
162 break;
163 case '/':
164 if (right.value == 0) {
165 sm_msg("internal error: %s: divide by zero", __func__);
166 ret.value = 123456789;
167 } else {
168 ret.value = left.value / right.value;
170 break;
171 case '+':
172 ret.value = left.value + right.value;
173 break;
174 case '-':
175 ret.value = left.value - right.value;
176 break;
177 case '%':
178 if (right.value == 0) {
179 sm_msg("internal error: %s: MOD by zero", __func__);
180 ret.value = 123456789;
181 } else {
182 ret.value = left.value % right.value;
184 break;
185 case '|':
186 ret.value = left.value | right.value;
187 break;
188 case '&':
189 ret.value = left.value & right.value;
190 break;
191 case SPECIAL_RIGHTSHIFT:
192 ret.value = left.value >> right.value;
193 break;
194 case SPECIAL_LEFTSHIFT:
195 ret.value = left.value << right.value;
196 break;
197 case '^':
198 ret.value = left.value ^ right.value;
199 break;
200 default:
201 sm_msg("internal error: %s: unhandled binop %s", __func__,
202 show_special(op));
203 ret.value = 1234567;
205 return ret;
208 const char *sval_to_str(sval_t sval)
210 static char buf[30];
212 if (sval_unsigned(sval) && sval.value == ULLONG_MAX)
213 return "u64max";
214 if (sval.value == LLONG_MAX)
215 return "s64max";
216 if (sval_unsigned(sval) && sval.value == UINT_MAX)
217 return "u32max";
218 if (sval.value == INT_MAX)
219 return "s32max";
220 if (sval_unsigned(sval) && sval.value == USHRT_MAX)
221 return "u16max";
223 if ((sval.type == &sshort_ctype || sval.type == &short_ctype) && sval.value == SHRT_MIN)
224 return "s16min";
225 if ((sval.type == &sint_ctype || sval.type == &int_ctype) && sval.value == INT_MIN)
226 return "s32min";
227 if (sval_signed(sval) && sval.value == LLONG_MIN)
228 return "s64min";
230 if (sval_unsigned(sval))
231 snprintf(buf, sizeof(buf), "%llu", sval.value);
232 else if (sval.value < 0)
233 snprintf(buf, sizeof(buf), "(%lld)", sval.value);
234 else
235 snprintf(buf, sizeof(buf), "%lld", sval.value);
237 return buf;
241 * This function is for compatibility. Eventually everything will use svals
242 * and we can get rid of whole_range.max.
244 long long sval_to_ll(sval_t sval)
246 if (sval_unsigned(sval) && sval.value == ULLONG_MAX)
247 return whole_range.max;
248 return sval.value;
251 static void free_svals(struct symbol *sym)
253 clear_sval_alloc();
256 void register_sval(int my_id)
258 add_hook(&free_svals, END_FUNC_HOOK);