OpenVPN
test_buffer.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2016-2021 Fox Crypto B.V. <openvpn@foxcrypto.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "syshead.h"
28
29#include <setjmp.h>
30#include <cmocka.h>
31
32#include "buffer.h"
33#include "buffer.c"
34#include "test_common.h"
35
36static void
38{
39 assert_true(strprefix("123456", "123456"));
40 assert_true(strprefix("123456", "123"));
41 assert_true(strprefix("123456", ""));
42 assert_false(strprefix("123456", "456"));
43 assert_false(strprefix("12", "123"));
44}
45
46#define testsep ","
47#define testnosep ""
48#define teststr1 "one"
49#define teststr2 "two"
50#define teststr3 "three"
51
52#define assert_buf_equals_str(buf, str) \
53 assert_int_equal(BLEN(buf), strlen(str)); \
54 assert_memory_equal(BPTR(buf), str, BLEN(buf));
55
56static void
58{
59 struct gc_arena gc = gc_new();
60 struct buffer buf = alloc_buf_gc(16, &gc);
61
62 buf_printf(&buf, "%d", 123);
63 buf_printf(&buf, "%s", "some text, too long to fit");
64 assert_buf_equals_str(&buf, "123some text, t");
65
66 buf_catrunc(&buf, "...");
67 assert_buf_equals_str(&buf, "123some text...");
68
69 buf_catrunc(&buf, "some other text, much too long to fit");
70 assert_buf_equals_str(&buf, "123some text...");
71
72 buf_catrunc(&buf, "something else"); /* exactly right */
73 assert_buf_equals_str(&buf, "1something else");
74
75 buf_catrunc(&buf, "something other"); /* 1 byte too long */
76 assert_buf_equals_str(&buf, "1something else");
77
78 gc_free(&gc);
79}
80
81static void
83{
84 const int input_size = 10;
85 const uint8_t input[] = { 0x01, 0x00, 0xff, 0x10, 0xff, 0x00, 0xf0, 0x0f, 0x09, 0x0a };
86 char *output;
87 struct gc_arena gc = gc_new();
88
89 int maxoutput = 0;
90 unsigned int blocksize = 5;
91 char *separator = " ";
92 output = format_hex_ex(input, input_size, maxoutput, blocksize, separator, &gc);
93 assert_string_equal(output, "0100ff10ff 00f00f090a");
94
95 maxoutput = 14;
96 output = format_hex_ex(input, input_size, maxoutput, blocksize, separator, &gc);
97 assert_string_equal(output, "0100[more...]");
98
99 maxoutput = 11;
100 output = format_hex_ex(input, input_size, maxoutput, blocksize, separator, &gc);
101 assert_string_equal(output, "0[more...]");
102
103 maxoutput = 10;
104 output = format_hex_ex(input, input_size, maxoutput, blocksize, separator, &gc);
105 assert_string_equal(output, "0100ff10f");
106
107 maxoutput = 9;
108 output = format_hex_ex(input, input_size, maxoutput, blocksize, separator, &gc);
109 assert_string_equal(output, "0100ff10");
110
111 gc_free(&gc);
112}
113
121
122static int
124{
125 struct test_buffer_list_aggregate_ctx *ctx = calloc(1, sizeof(*ctx));
126 ctx->empty = buffer_list_new();
127
132
136
138 uint8_t data = 0;
139 buffer_list_push_data(ctx->empty_buffers, &data, 0);
140 buffer_list_push_data(ctx->empty_buffers, &data, 0);
141
142 *state = ctx;
143 return 0;
144}
145
146static int
148{
149 struct test_buffer_list_aggregate_ctx *ctx = *state;
150
155 free(ctx);
156 return 0;
157}
158
159static void
161{
162 struct test_buffer_list_aggregate_ctx *ctx = *state;
163
164 /* aggregating an empty buffer list results in an empty buffer list */
166 assert_null(ctx->empty->head);
167}
168
169static void
171{
172 struct test_buffer_list_aggregate_ctx *ctx = *state;
173
174 /* With a max length of 2, no aggregation should take place */
176 assert_int_equal(ctx->one_two_three->size, 3);
177 struct buffer *buf = buffer_list_peek(ctx->one_two_three);
179}
180
181static void
183{
184 struct test_buffer_list_aggregate_ctx *ctx = *state;
185 const char *expected = teststr1 testsep teststr2 testsep;
186
187 /* Aggregate the first two elements
188 * (add 1 to max_len to test if "three" is not sneaked in too)
189 */
190 buffer_list_aggregate_separator(ctx->one_two_three, strlen(expected) + 1, testsep);
191 assert_int_equal(ctx->one_two_three->size, 2);
192 struct buffer *buf = buffer_list_peek(ctx->one_two_three);
194}
195
196static void
198{
199 struct test_buffer_list_aggregate_ctx *ctx = *state;
200
201 /* Aggregate all */
203 assert_int_equal(ctx->one_two_three->size, 1);
204 struct buffer *buf = buffer_list_peek(ctx->one_two_three);
206}
207
208static void
210{
211 struct test_buffer_list_aggregate_ctx *ctx = *state;
212
213 /* Aggregate all */
215 assert_int_equal(ctx->one_two_three->size, 1);
216 struct buffer *buf = buffer_list_peek(ctx->one_two_three);
218}
219
220static void
222{
223 struct test_buffer_list_aggregate_ctx *ctx = *state;
224 struct buffer_list *bl_zerolen = ctx->zero_length_strings;
225
226 /* Aggregate all */
227 buffer_list_aggregate_separator(bl_zerolen, 1 << 16, testnosep);
228 assert_int_equal(bl_zerolen->size, 1);
229 struct buffer *buf = buffer_list_peek(bl_zerolen);
230 assert_buf_equals_str(buf, "");
231}
232
233static void
235{
236 struct test_buffer_list_aggregate_ctx *ctx = *state;
237 struct buffer_list *bl_emptybuffers = ctx->empty_buffers;
238
239 /* Aggregate all */
240 buffer_list_aggregate_separator(bl_emptybuffers, 1 << 16, testnosep);
241 assert_int_equal(bl_emptybuffers->size, 1);
243 assert_int_equal(BLEN(buf), 0);
244}
245
246static void
248{
249 struct gc_arena gc = gc_new();
250 struct buffer buf = alloc_buf_gc(1024, &gc);
251
252 assert_ptr_equal(gc.list + 1, buf.data);
253 free_buf_gc(&buf, &gc);
255
256 gc_free(&gc);
257}
258
259static void
261{
262 struct gc_arena gc = gc_new();
263 struct buffer buf1 = alloc_buf_gc(1024, &gc);
264 struct buffer buf2 = alloc_buf_gc(1024, &gc);
265 struct buffer buf3 = alloc_buf_gc(1024, &gc);
266
267 struct gc_entry *e;
268
269 e = gc.list;
270
271 assert_ptr_equal(e + 1, buf3.data);
272 assert_ptr_equal(e->next + 1, buf2.data);
273 assert_ptr_equal(e->next->next + 1, buf1.data);
274
275 free_buf_gc(&buf2, &gc);
276
277 assert_non_null(gc.list);
278
279 while (e)
280 {
281 assert_ptr_not_equal(e + 1, buf2.data);
282 e = e->next;
283 }
284
285 gc_free(&gc);
286}
287
288
289static void
291{
292 struct gc_arena gc = gc_new();
293
294 void *p1 = gc_realloc(NULL, 512, &gc);
295 void *p2 = gc_realloc(NULL, 512, &gc);
296
297 assert_ptr_not_equal(p1, p2);
298
299 memset(p1, '1', 512);
300 memset(p2, '2', 512);
301
302 p1 = gc_realloc(p1, 512, &gc);
303
304 /* allocate 512kB to ensure the pointer needs to change */
305 void *p1new = gc_realloc(p1, 512ul * 1024, &gc);
306 assert_ptr_not_equal(p1, p1new);
307
308 void *p2new = gc_realloc(p2, 512ul * 1024, &gc);
309 assert_ptr_not_equal(p2, p2new);
310
311 void *p3 = gc_realloc(NULL, 512, &gc);
312 memset(p3, '3', 512);
313
314
315 gc_free(&gc);
316}
317
318static void
320{
321 char buf[256];
322 strcpy(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
323 assert_false(string_mod(buf, CC_PRINT, 0, '@'));
324 assert_string_equal(buf, "There is @ a nice 1234 year old tr@ ee!");
325
326 strcpy(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
327 assert_true(string_mod(buf, CC_ANY, 0, '@'));
328 assert_string_equal(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
329
330 /* 0 as replace removes characters */
331 strcpy(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
332 assert_false(string_mod(buf, CC_PRINT, 0, '\0'));
333 assert_string_equal(buf, "There is a nice 1234 year old tr ee!");
334
335 strcpy(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
336 assert_false(string_mod(buf, CC_PRINT, CC_DIGIT, '@'));
337 assert_string_equal(buf, "There is @ a nice @@@@ year old tr@ ee!");
338
339 strcpy(buf, "There is \x01 a nice 1234 year old tr\x7f ee!");
340 assert_false(string_mod(buf, CC_ALPHA, CC_DIGIT, '.'));
341 assert_string_equal(buf, "There.is...a.nice......year.old.tr..ee.");
342
343 strcpy(buf, "There is \x01 a 'nice' \"1234\"\n year old \ntr\x7f ee!");
344 assert_false(string_mod(buf, CC_ALPHA | CC_DIGIT | CC_NEWLINE | CC_SINGLE_QUOTE,
345 CC_DOUBLE_QUOTE | CC_BLANK, '.'));
346 assert_string_equal(buf, "There.is...a.'nice'..1234.\n.year.old.\ntr..ee.");
347
348 strcpy(buf, "There is a \\'nice\\' \"1234\" [*] year old \ntree!");
349 assert_false(string_mod(buf, CC_PRINT, CC_BACKSLASH | CC_ASTERISK, '.'));
350 assert_string_equal(buf, "There is a .'nice.' \"1234\" [.] year old .tree!");
351}
352
353
354static void
356{
357 struct gc_arena gc = gc_new();
358
359 struct buffer buf = alloc_buf_gc(1024, &gc);
360
361 const char test1[] = "There is a nice 1234\x00 year old tree!";
362 buf_write(&buf, test1, sizeof(test1));
363
364 /* allow the null bytes and string but not the ! */
366
367 /* remove final ! and null byte to pass */
368 buf_inc_len(&buf, -2);
370
371 /* Check excluding digits works */
373 gc_free(&gc);
374}
375
376static void
377test_snprintf(void **state)
378{
379 /* we used to have a custom openvpn_snprintf function because some
380 * OS (the comment did not specify which) did not always put the
381 * null byte there. So we unit test this to be sure.
382 *
383 * This probably refers to the MSVC behaviour, see also
384 * https://stackoverflow.com/questions/7706936/is-snprintf-always-null-terminating
385 */
386
387 /* Instead of trying to trick the compiler here, disable the warnings
388 * for this unit test. We know that the results will be truncated
389 * and we want to test that. Not we need the clang as clang-cl (msvc) does
390 * not define __GNUC__ like it does under UNIX(-like) platforms */
391#if defined(__GNUC__) || defined(__clang__)
392/* some clang version do not understand -Wformat-truncation, so ignore the
393 * warning to avoid warnings/errors (-Werror) about unknown pragma/option */
394#if defined(__clang__)
395#pragma clang diagnostic push
396#pragma clang diagnostic ignored "-Wunknown-warning-option"
397#endif
398#pragma GCC diagnostic push
399#pragma GCC diagnostic ignored "-Wformat-truncation"
400#endif
401
402 char buf[10] = { 'a' };
403 int ret = 0;
404
405 ret = snprintf(buf, sizeof(buf), "0123456789abcde");
406 assert_int_equal(ret, 15);
407 assert_int_equal(buf[9], '\0');
408
409 memset(buf, 'b', sizeof(buf));
410 ret = snprintf(buf, sizeof(buf), "- %d - %d -", 77, 88);
411 assert_int_equal(ret, 11);
412 assert_int_equal(buf[9], '\0');
413
414 memset(buf, 'c', sizeof(buf));
415 ret = snprintf(buf, sizeof(buf), "- %8.2f", 77.8899);
416 assert_int_equal(ret, 10);
417 assert_int_equal(buf[9], '\0');
418
419#if defined(__GNUC__) || defined(__clang__)
420#pragma GCC diagnostic pop
421#if defined(__clang__)
422#pragma clang diagnostic pop
423#endif
424#endif
425}
426
427void
428test_buffer_chomp(void **state)
429{
430 struct gc_arena gc = gc_new();
431 struct buffer buf = alloc_buf_gc(1024, &gc);
432
433 const char test1[] = "There is a nice 1234 year old tree!\n\r";
434 buf_write(&buf, test1, sizeof(test1));
435 buf_chomp(&buf);
436 /* Check that our own method agrees */
438 assert_string_equal(BSTR(&buf), "There is a nice 1234 year old tree!");
439
440 struct buffer buf2 = alloc_buf_gc(1024, &gc);
441 const char test2[] = "CR_RESPONSE,MTIx\x0a\x00";
442 buf_write(&buf2, test2, sizeof(test2));
443 buf_chomp(&buf2);
444
445 buf_chomp(&buf2);
446 /* Check that our own method agrees */
448 assert_string_equal(BSTR(&buf2), "CR_RESPONSE,MTIx");
449
450 gc_free(&gc);
451}
452
453int
454main(void)
455{
457 const struct CMUnitTest tests[] = {
458 cmocka_unit_test(test_buffer_strprefix),
459 cmocka_unit_test(test_buffer_printf_catrunc),
460 cmocka_unit_test(test_buffer_format_hex_ex),
461 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_empty,
463 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_noop,
465 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_two,
467 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_all,
469 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_nosep,
471 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_zerolen,
473 cmocka_unit_test_setup_teardown(test_buffer_list_aggregate_separator_emptybuffers,
475 cmocka_unit_test(test_buffer_free_gc_one),
476 cmocka_unit_test(test_buffer_free_gc_two),
477 cmocka_unit_test(test_buffer_gc_realloc),
478 cmocka_unit_test(test_character_class),
479 cmocka_unit_test(test_character_string_mod_buf),
480 cmocka_unit_test(test_snprintf),
481 cmocka_unit_test(test_buffer_chomp)
482 };
483
484 return cmocka_run_group_tests_name("buffer", tests, NULL, NULL);
485}
struct buffer_entry * buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
Allocates and appends a new buffer containing data of length size.
Definition buffer.c:1203
void buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len, const char *sep)
Aggregates as many buffers as possible from bl in a new buffer of maximum length max_len .
Definition buffer.c:1243
static void free_buf_gc(struct buffer *buf, struct gc_arena *gc)
Definition buffer.c:191
void buf_catrunc(struct buffer *buf, const char *str)
Definition buffer.c:288
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:241
void * gc_realloc(void *ptr, size_t size, struct gc_arena *a)
allows to realloc a pointer previously allocated by gc_malloc or gc_realloc
Definition buffer.c:370
char * format_hex_ex(const uint8_t *data, int size, int maxoutput, unsigned int space_break_flags, const char *separator, struct gc_arena *gc)
Definition buffer.c:483
struct buffer_list * buffer_list_new(void)
Allocate an empty buffer list of capacity max_size.
Definition buffer.c:1149
struct buffer * buffer_list_peek(struct buffer_list *ol)
Retrieve the head buffer.
Definition buffer.c:1230
bool string_check_buf(struct buffer *buf, const unsigned int inclusive, const unsigned int exclusive)
Check a buffer if it only consists of allowed characters.
Definition buffer.c:1074
void buffer_list_free(struct buffer_list *ol)
Frees a buffer list and all the buffers in it.
Definition buffer.c:1158
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:89
bool string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
Modifies a string in place by replacing certain classes of characters of it with a specified characte...
Definition buffer.c:1041
void buffer_list_push(struct buffer_list *ol, const char *str)
Allocates and appends a new buffer containing str as data to ol.
Definition buffer.c:1189
void buf_chomp(struct buffer *buf)
Definition buffer.c:554
#define CC_DOUBLE_QUOTE
double quote
Definition buffer.h:892
#define CC_BLANK
space or tab
Definition buffer.h:880
#define BSTR(buf)
Definition buffer.h:128
#define CC_ANY
any character
Definition buffer.h:867
#define CC_SINGLE_QUOTE
single quote
Definition buffer.h:891
static bool buf_inc_len(struct buffer *buf, int inc)
Definition buffer.h:588
#define CC_DIGIT
digit isdigit()
Definition buffer.h:874
#define CC_CRLF
carriage return or newline
Definition buffer.h:904
#define CC_ASTERISK
asterisk
Definition buffer.h:900
#define CC_ALPHA
alphabetic isalpha()
Definition buffer.h:871
#define CC_NEWLINE
newline
Definition buffer.h:881
#define CC_SPACE
whitespace isspace()
Definition buffer.h:877
static bool buf_write(struct buffer *dest, const void *src, size_t size)
Definition buffer.h:660
#define CC_BACKSLASH
backslash
Definition buffer.h:884
#define BLEN(buf)
Definition buffer.h:126
#define CC_NULL
null character \0
Definition buffer.h:868
static void gc_free(struct gc_arena *a)
Definition buffer.h:1015
#define CC_PRINT
printable (>= 32, != 127)
Definition buffer.h:875
#define CC_ALNUM
alphanumeric isalnum()
Definition buffer.h:870
static bool strprefix(const char *str, const char *prefix)
Return true iff str starts with prefix.
Definition buffer.h:959
static struct gc_arena gc_new(void)
Definition buffer.h:1007
struct buffer_entry * head
Definition buffer.h:1104
Wrapper structure for dynamically allocated memory.
Definition buffer.h:60
uint8_t * data
Pointer to the allocated memory.
Definition buffer.h:67
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:65
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:116
struct gc_entry * list
First element of the linked list of gc_entry structures.
Definition buffer.h:117
Garbage collection entry for one dynamically allocated block of memory.
Definition buffer.h:87
struct gc_entry * next
Pointer to the next item in the linked list.
Definition buffer.h:88
struct buffer_list * zero_length_strings
struct buffer_list * one_two_three
struct buffer_list * empty
struct buffer_list * empty_buffers
static void test_character_class(void **state)
static void test_buffer_format_hex_ex(void **state)
Definition test_buffer.c:82
static int test_buffer_list_setup(void **state)
static void test_buffer_list_aggregate_separator_all(void **state)
#define assert_buf_equals_str(buf, str)
Definition test_buffer.c:52
static void test_buffer_free_gc_two(void **state)
static void test_snprintf(void **state)
static void test_character_string_mod_buf(void **state)
#define teststr1
Definition test_buffer.c:48
static void test_buffer_list_aggregate_separator_zerolen(void **state)
static void test_buffer_printf_catrunc(void **state)
Definition test_buffer.c:57
void test_buffer_chomp(void **state)
int main(void)
static void test_buffer_list_aggregate_separator_two(void **state)
#define testnosep
Definition test_buffer.c:47
static void test_buffer_list_aggregate_separator_noop(void **state)
static void test_buffer_free_gc_one(void **state)
#define teststr2
Definition test_buffer.c:49
static void test_buffer_list_aggregate_separator_nosep(void **state)
static void test_buffer_gc_realloc(void **state)
static void test_buffer_list_aggregate_separator_empty(void **state)
static int test_buffer_list_teardown(void **state)
static void test_buffer_list_aggregate_separator_emptybuffers(void **state)
static void test_buffer_strprefix(void **state)
Definition test_buffer.c:37
#define teststr3
Definition test_buffer.c:50
#define testsep
Definition test_buffer.c:46
static void openvpn_unit_test_setup(void)
Sets up the environment for unit tests like making both stderr and stdout non-buffered to avoid messa...
Definition test_common.h:35
struct gc_arena gc
Definition test_ssl.c:154