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