1 /* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */
2
3 #include "test-lib.h"
4
5
6 #define INVALID(n) { #n, -1, 0 }
7 #define VALID(n) { #n, 0, n }
8
9 /* always pads with leading zeros to a size of 9 digits */
crappy_uintmax_to_str(char * into,uintmax_t val)10 static int crappy_uintmax_to_str(char *into, uintmax_t val)
11 {
12 #define BIGBASE 1000000000ull
13 #define STRINGIFY(s) #s
14 #define STRINGIFY2(s) STRINGIFY(s)
15 int len = 0;
16 if(val >= BIGBASE) {
17 len = crappy_uintmax_to_str(into, val/BIGBASE);
18 }
19 i_snprintf(into + len, 10, "%09llu",
20 (unsigned long long)(val % BIGBASE));
21 return len + strlen(STRINGIFY2(BIGBASE))-4;
22 #undef STRINGIFY2
23 #undef STRINGIFY
24 #undef BIGBASE
25 }
test_str_to_uintmax(void)26 static void test_str_to_uintmax(void)
27 {
28 unsigned int i=0;
29 int randrange = i_rand_minmax(1, 15); /* when 1, will max out on 1s */
30 uintmax_t value = 0, valbase = i_rand() * 1000ull;
31 int len, ret;
32 char buff[50]; /* totally assumes < 159 bits */
33
34 test_begin("str_to_uintmax in range");
35 while (i < sizeof(uintmax_t)*CHAR_BIT) {
36 uintmax_t value_back;
37 const char *endp;
38
39 value = (value << 1) + 1;
40 if (value >= 64)
41 value -= i_rand_limit(randrange); /* don't always test the same numbers */
42 len = crappy_uintmax_to_str(buff, value);
43 ret = str_to_uintmax(buff, &value_back);
44 test_assert_idx(ret == 0, i);
45 test_assert_idx(value == value_back, i);
46
47 /* test with trailing noise */
48 buff[len] = 'x'; /* don't even null-terminate, let's be evil */
49 value_back = 0x1234567890123456;
50 ret = str_to_uintmax(buff, &value_back);
51 test_assert_idx(ret < 0, i);
52 test_assert_idx(value_back == 0x1234567890123456, i);
53 ret = str_parse_uintmax(buff, &value_back, &endp);
54 test_assert_idx(ret == 0, i);
55 test_assert_idx(value_back == value, i);
56 test_assert_idx(endp == &buff[len], i);
57 i++;
58 }
59 test_end();
60
61 /* not knowing exactly how large a uintmax_t is, we have to construct
62 the troublesome near-10/9*MAX strings manually by appending digits
63 to a MAX/9 string which we can easily create. Do a wider range
64 of 30 rather than the obvious 10, just in case - all are too large.*/
65 test_begin("str_to_uintmax overflow corner case");
66 value = UINTMAX_MAX/9-1;
67 len = crappy_uintmax_to_str(buff, value);
68 buff[len] = '0';
69 buff[len+1] = '\0';
70 for(i = 0; i <= 30; ++i) {
71 int j = len + 1;
72 while (buff[--j] == '9')
73 buff[j] = '0';
74 buff[j]++;
75 value = valbase + i;
76 ret = str_to_uintmax(buff, &value);
77 test_assert_idx(ret < 0 && value == valbase + i, i);
78 }
79 test_end();
80 }
81
82 /* always pads with leading zeros to a size of 9 digits */
crappy_uintmax_to_str_hex(char * into,uintmax_t val)83 static int crappy_uintmax_to_str_hex(char *into, uintmax_t val)
84 {
85 #define BIGBASE 0x1000000000ull
86 #define STRINGIFY(s) #s
87 #define STRINGIFY2(s) STRINGIFY(s)
88 int len = 0;
89 if(val >= BIGBASE) {
90 len = crappy_uintmax_to_str_hex(into, val/BIGBASE);
91 }
92 i_snprintf(into + len, 10, "%09llx",
93 (unsigned long long)(val % BIGBASE));
94 return len + strlen(STRINGIFY2(BIGBASE))-6;
95 #undef STRINGIFY2
96 #undef STRINGIFY
97 #undef BIGBASE
98 }
test_str_to_uintmax_hex(void)99 static void test_str_to_uintmax_hex(void)
100 {
101 unsigned int i=0;
102 int randrange = i_rand_minmax(1, 15); /* when 1, will max out on 1s */
103 uintmax_t value = 0, valbase = i_rand() * 1000ull;
104 int len, ret;
105 char buff[52]; /* totally assumes < 200 bits */
106
107 test_begin("str_to_uintmax_hex in range");
108 while (i < sizeof(uintmax_t)*CHAR_BIT) {
109 uintmax_t value_back;
110 const char *endp;
111
112 value = (value << 1) + 1;
113 if (value >= 64)
114 value -= i_rand_limit(randrange); /* don't always test the same numbers */
115 len = crappy_uintmax_to_str_hex(buff, value);
116 ret = str_to_uintmax_hex(buff, &value_back);
117 test_assert_idx(ret == 0, i);
118 test_assert_idx(value == value_back, i);
119
120 /* test with trailing noise */
121 buff[len] = 'x'; /* don't even null-terminate, let's be evil */
122 value_back = 0x1234567890123456;
123 ret = str_to_uintmax_hex(buff, &value_back);
124 test_assert_idx(ret < 0, i);
125 test_assert_idx(value_back == 0x1234567890123456, i);
126 ret = str_parse_uintmax_hex(buff, &value_back, &endp);
127 test_assert_idx(ret == 0, i);
128 test_assert_idx(value_back == value, i);
129 test_assert_idx(endp == &buff[len], i);
130 i++;
131 }
132 test_end();
133
134 /* not knowing exactly how large a uintmax_t is, we have to construct
135 the troublesome near-0x10/0x0F*MAX strings manually by appending digits
136 to a MAX/0x0f string which we can easily create. Do a wider range
137 of 0x30 rather than the obvious 0x10, just in case - all are too large.*/
138 test_begin("str_to_uintmax_hex overflow corner case");
139 value = (UINTMAX_MAX/0x0f)-1;
140 len = crappy_uintmax_to_str_hex(buff, value);
141 buff[len] = '0';
142 buff[len+1] = '\0';
143 for(i = 0; i <= 0x30; ++i) {
144 int j = len + 1;
145 while (buff[--j] == 'f')
146 buff[j] = '0';
147 if (buff[j] == '9')
148 buff[j] = 'a';
149 else
150 buff[j]++;
151 value = valbase + i;
152 ret = str_to_uintmax_hex(buff, &value);
153 test_assert_idx(ret < 0 && value == valbase + i, i);
154 }
155 test_end();
156 }
157
158 /* always pads with leading zeros to a size of 9 digits */
crappy_uintmax_to_str_oct(char * into,uintmax_t val)159 static int crappy_uintmax_to_str_oct(char *into, uintmax_t val)
160 {
161 #define BIGBASE 01000000000ull
162 #define STRINGIFY(s) #s
163 #define STRINGIFY2(s) STRINGIFY(s)
164 int len = 0;
165 if(val >= BIGBASE) {
166 len = crappy_uintmax_to_str_oct(into, val/BIGBASE);
167 }
168 i_snprintf(into + len, 10, "%09llo",
169 (unsigned long long)(val % BIGBASE));
170 return len + strlen(STRINGIFY2(BIGBASE))-5;
171 #undef STRINGIFY2
172 #undef STRINGIFY
173 #undef BIGBASE
174 }
test_str_to_uintmax_oct(void)175 static void test_str_to_uintmax_oct(void)
176 {
177 unsigned int i=0;
178 int randrange = i_rand_minmax(1, 15); /* when 1, will max out on 1s */
179 uintmax_t value = 0, valbase = i_rand() * 1000ull;
180 int len, ret;
181 char buff[69]; /* totally assumes < 200 bits */
182
183 test_begin("str_to_uintmax_oct in range");
184 while (i < sizeof(uintmax_t)*CHAR_BIT) {
185 uintmax_t value_back;
186 const char *endp = NULL;
187
188 value = (value << 1) + 1;
189 if (value >= 64)
190 value -= i_rand_limit(randrange); /* don't always test the same numbers */
191 len = crappy_uintmax_to_str_oct(buff, value);
192 ret = str_to_uintmax_oct(buff, &value_back);
193 test_assert_idx(ret == 0, i);
194 test_assert_idx(value == value_back, i);
195
196 /* test with trailing noise */
197 buff[len] = 'x'; /* don't even null-terminate, let's be evil */
198 value_back = 0x1234567890123456;
199 ret = str_to_uintmax_oct(buff, &value_back);
200 test_assert_idx(ret < 0, i);
201 test_assert_idx(value_back == 0x1234567890123456, i);
202 ret = str_parse_uintmax_oct(buff, &value_back, &endp);
203 test_assert_idx(ret == 0, i);
204 test_assert_idx(value_back == value, i);
205 test_assert_idx(endp == &buff[len], i);
206 i++;
207 }
208 test_end();
209
210 /* not knowing exactly how large a uintmax_t is, we have to construct
211 the troublesome near-010/007*MAX strings manually by appending digits
212 to a MAX/007 string which we can easily create. Do a wider range
213 of 030 rather than the obvious 010, just in case - all are too large.*/
214 test_begin("str_to_uintmax_oct overflow corner case");
215 value = (UINTMAX_MAX/007)-1;
216 len = crappy_uintmax_to_str_oct(buff, value);
217 buff[len] = '0';
218 buff[len+1] = '\0';
219 for(i = 0; i <= 030; ++i) {
220 int j = len + 1;
221 while (buff[--j] == '7')
222 buff[j] = '0';
223 buff[j]++;
224 value = valbase + i;
225 ret = str_to_uintmax_oct(buff, &value);
226 test_assert_idx(ret < 0 && value == valbase + i, i);
227 }
228 test_end();
229 }
230
test_str_to_u64(void)231 static void test_str_to_u64(void)
232 {
233 unsigned int i;
234 const struct {
235 const char *input;
236 int ret;
237 uint64_t val;
238 } u64tests[] = {
239 INVALID(-1),
240 INVALID(foo),
241 VALID(0),
242 VALID(000000000000000000000000000000000000000000000000000000000000000),
243 { "000000000000000000000000000000000000000000000000000001000000001", 0, 1000000001 },
244 { "18446744073709551615", 0, 18446744073709551615ULL },
245 INVALID(18446744073709551616),
246 INVALID(20496382304121724010), /* 2^64*10/9 doesn't wrap */
247 INVALID(20496382304121724017), /* 2^64*10/9 wraps only after addition */
248 INVALID(20496382304121724020), /* 2^64*10/9 wraps on multiply*/
249 };
250 test_begin("str_to_uint64");
251 for (i = 0; i < N_ELEMENTS(u64tests); ++i) {
252 uint64_t val = 0xBADBEEF15BADF00D;
253 int ret = str_to_uint64(u64tests[i].input, &val);
254 test_assert_idx(ret == u64tests[i].ret, i);
255 if (ret == 0)
256 test_assert_idx(val == u64tests[i].val, i);
257 else
258 test_assert_idx(val == 0xBADBEEF15BADF00D, i);
259
260 if (ret == 0)
261 T_BEGIN {
262 const char *longer = t_strconcat(u64tests[i].input, "x", NULL);
263 ret = str_to_uint64(longer, &val);
264 test_assert_idx(ret < 0, i);
265 } T_END;
266 }
267 test_end();
268 }
269
test_str_to_u32(void)270 static void test_str_to_u32(void)
271 {
272 unsigned int i;
273 const struct {
274 const char *input;
275 int ret;
276 uint32_t val;
277 } u32tests[] = {
278 VALID(0),
279 INVALID(-0),
280 VALID(4294967295),
281 INVALID(4294967296),
282 INVALID(4772185880),
283 INVALID(4772185884),
284 INVALID(4772185890),
285 };
286 test_begin("str_to_uint32");
287 for (i = 0; i < N_ELEMENTS(u32tests); ++i) {
288 uint32_t val = 0xDEADF00D;
289 int ret = str_to_uint32(u32tests[i].input, &val);
290 test_assert_idx(ret == u32tests[i].ret, i);
291 if (ret == 0)
292 test_assert_idx(val == u32tests[i].val, i);
293 else
294 test_assert_idx(val == 0xDEADF00D, i);
295 }
296 test_end();
297 }
298
299 /* Assumes long long is 64 bit, 2's complement */
test_str_to_llong(void)300 static void test_str_to_llong(void)
301 {
302 unsigned int i;
303 const struct {
304 const char *input;
305 int ret;
306 long long val;
307 } i64tests[] = {
308 VALID(0),
309 VALID(-0),
310 INVALID(--0),
311 VALID(2147483648),
312 VALID(-2147483649),
313 VALID(9223372036854775807),
314 { "-9223372036854775808", 0, -9223372036854775807-1 },
315 INVALID(9223372036854775808),
316 INVALID(-9223372036854775809),
317 };
318 test_begin("str_to_llong");
319 for (i = 0; i < N_ELEMENTS(i64tests); ++i) {
320 long long val = 123456789;
321 int ret = str_to_llong(i64tests[i].input, &val);
322 test_assert_idx(ret == i64tests[i].ret, i);
323 if (ret == 0)
324 test_assert_idx(val == i64tests[i].val, i);
325 else
326 test_assert_idx(val == 123456789, i);
327 }
328 test_end();
329 }
330
331 /* Assumes int is 32 bit, 2's complement */
test_str_to_i32(void)332 static void test_str_to_i32(void)
333 {
334 unsigned int i;
335 const struct {
336 const char *input;
337 int ret;
338 int val;
339 } i32tests[] = {
340 VALID(0),
341 VALID(-0),
342 INVALID(--0),
343 VALID(2147483647),
344 VALID(-2147483648),
345 INVALID(2147483648),
346 INVALID(-2147483649),
347 };
348 test_begin("str_to_int");
349 for (i = 0; i < N_ELEMENTS(i32tests); ++i) {
350 int val = 123456789;
351 int ret = str_to_int(i32tests[i].input, &val);
352 test_assert_idx(ret == i32tests[i].ret, i);
353 if (ret == 0)
354 test_assert_idx(val == i32tests[i].val, i);
355 else
356 test_assert_idx(val == 123456789, i);
357 }
358 test_end();
359 }
360
test_str_is_float(void)361 static void test_str_is_float(void)
362 {
363 test_begin("str_is_float accepts integer");
364 /* accepts integer */
365 test_assert(str_is_float("0",'\0'));
366 test_assert(str_is_float("1234",'\0'));
367 test_end();
368 test_begin("str_is_float accepts float");
369 test_assert(str_is_float("0.0",'\0'));
370 test_assert(str_is_float("1234.0",'\0'));
371 test_assert(str_is_float("0.1234",'\0'));
372 test_assert(str_is_float("1234.1234",'\0'));
373 test_assert(str_is_float("0.1234 ",' '));
374 test_assert(str_is_float("1234.1234",'.'));
375 test_end();
376 test_begin("str_is_float refuses invalid values");
377 test_assert(!str_is_float(".",'\0'));
378 test_assert(!str_is_float(".1234",'\0'));
379 test_assert(!str_is_float("1234.",'\0'));
380 test_assert(!str_is_float("i am not a float at all",'\0'));
381 test_assert(!str_is_float("0x1234.0x1234",'\0'));
382 test_assert(!str_is_float(".0",'\0'));
383 test_assert(!str_is_float("0.",'\0'));
384 test_end();
385 }
386
test_strnum(void)387 void test_strnum(void)
388 {
389 /* If the above isn't true, then we do expect some failures possibly */
390 test_str_to_uintmax();
391 test_str_to_uintmax_hex();
392 test_str_to_uintmax_oct();
393 test_str_to_u64();
394 test_str_to_u32();
395 test_str_to_llong();
396 test_str_to_i32();
397 test_str_is_float();
398 }
399