test_alloc.c revision 1.2
1/*	$NetBSD: test_alloc.c,v 1.2 2018/04/07 22:37:29 christos Exp $	*/
2
3/*
4 * Copyright (c) 2007-2017 by Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18/*
19 * We test the functions provided in alloc.c here. These are very
20 * basic functions, and it is very important that they work correctly.
21 *
22 * You can see two different styles of testing:
23 *
24 * - In the first, we have a single test for each function that tests
25 *   all of the possible ways it can operate. (This is the case for
26 *   the buffer tests.)
27 *
28 * - In the second, we have a separate test for each of the ways a
29 *   function can operate. (This is the case for the data_string
30 *   tests.)
31 *
32 * The advantage of a single test per function is that you have fewer
33 * tests, and less duplicated and extra code. The advantage of having
34 * a separate test is that each test is simpler. Plus if you need to
35 * allow certain tests to fail for some reason (known bugs that are
36 * hard to fix for example), then
37 */
38
39/** @TODO: dmalloc() test */
40
41#include "config.h"
42#include <atf-c.h>
43#include "dhcpd.h"
44#include "omapip/alloc.h"
45
46static const char* checkString (struct data_string* ds, const char *src);
47
48ATF_TC(buffer_allocate);
49
50ATF_TC_HEAD(buffer_allocate, tc) {
51    atf_tc_set_md_var(tc, "descr", "buffer_allocate basic test");
52}
53
54ATF_TC_BODY(buffer_allocate, tc) {
55    struct buffer *buf = 0;
56
57    /*
58     * Check a 0-length buffer.
59     */
60    buf = NULL;
61    if (!buffer_allocate(&buf, 0, MDL)) {
62        atf_tc_fail("failed on 0-len buffer");
63    }
64    if (!buffer_dereference(&buf, MDL)) {
65        atf_tc_fail("buffer_dereference() failed");
66    }
67    if (buf != NULL) {
68        atf_tc_fail("buffer_dereference() did not NULL-out buffer");
69    }
70
71    /*
72     * Check an actual buffer.
73     */
74    buf = NULL;
75    if (!buffer_allocate(&buf, 100, MDL)) {
76        atf_tc_fail("failed on allocate 100 bytes\n");
77    }
78    if (!buffer_dereference(&buf, MDL)) {
79        atf_tc_fail("buffer_dereference() failed");
80    }
81    if (buf != NULL) {
82        atf_tc_fail("buffer_dereference() did not NULL-out buffer");
83    }
84
85    /*
86     * Okay, we're happy.
87     */
88    atf_tc_pass();
89}
90
91ATF_TC(buffer_reference);
92
93ATF_TC_HEAD(buffer_reference, tc) {
94    atf_tc_set_md_var(tc, "descr", "buffer_reference basic test");
95}
96
97ATF_TC_BODY(buffer_reference, tc) {
98
99    struct buffer *a, *b;
100
101    /*
102     * Create a buffer.
103     */
104    a = NULL;
105    if (!buffer_allocate(&a, 100, MDL)) {
106        atf_tc_fail("failed on allocate 100 bytes");
107    }
108
109    /**
110     * Confirm buffer_reference() doesn't work if we pass in NULL.
111     *
112     * @TODO: we should confirm we get an error message here.
113     */
114    if (buffer_reference(NULL, a, MDL)) {
115        atf_tc_fail("succeeded on an error input");
116    }
117
118    /**
119     * @TODO: we should confirm we get an error message if we pass
120     *       a non-NULL target.
121     */
122
123    /*
124     * Confirm we work under normal circumstances.
125     */
126    b = NULL;
127    if (!buffer_reference(&b, a, MDL)) {
128        atf_tc_fail("buffer_reference() failed");
129    }
130
131    if (b != a) {
132        atf_tc_fail("incorrect pointer returned");
133    }
134
135    if (b->refcnt != 2) {
136        atf_tc_fail("incorrect refcnt");
137    }
138
139    /*
140     * Clean up.
141     */
142    if (!buffer_dereference(&b, MDL)) {
143        atf_tc_fail("buffer_dereference() failed");
144    }
145    if (!buffer_dereference(&a, MDL)) {
146        atf_tc_fail("buffer_dereference() failed");
147    }
148
149}
150
151
152ATF_TC(buffer_dereference);
153
154ATF_TC_HEAD(buffer_dereference, tc) {
155    atf_tc_set_md_var(tc, "descr", "buffer_dereference basic test");
156}
157
158ATF_TC_BODY(buffer_dereference, tc) {
159    struct buffer *a, *b;
160
161    /**
162     * Confirm buffer_dereference() doesn't work if we pass in NULL.
163     *
164     * TODO: we should confirm we get an error message here.
165     */
166    if (buffer_dereference(NULL, MDL)) {
167        atf_tc_fail("succeeded on an error input");
168    }
169
170    /**
171     * Confirm buffer_dereference() doesn't work if we pass in
172     * a pointer to NULL.
173     *
174     * @TODO: we should confirm we get an error message here.
175     */
176    a = NULL;
177    if (buffer_dereference(&a, MDL)) {
178        atf_tc_fail("succeeded on an error input");
179    }
180
181    /*
182     * Confirm we work under normal circumstances.
183     */
184    a = NULL;
185    if (!buffer_allocate(&a, 100, MDL)) {
186        atf_tc_fail("failed on allocate");
187    }
188    if (!buffer_dereference(&a, MDL)) {
189        atf_tc_fail("buffer_dereference() failed");
190    }
191    if (a != NULL) {
192        atf_tc_fail("non-null buffer after buffer_dereference()");
193    }
194
195    /**
196     * Confirm we get an error from negative refcnt.
197     *
198     * @TODO: we should confirm we get an error message here.
199     */
200    a = NULL;
201    if (!buffer_allocate(&a, 100, MDL)) {
202        atf_tc_fail("failed on allocate");
203    }
204    b = NULL;
205    if (!buffer_reference(&b, a, MDL)) {
206        atf_tc_fail("buffer_reference() failed");
207    }
208    a->refcnt = 0;    /* purposely set to invalid value */
209    if (buffer_dereference(&a, MDL)) {
210        atf_tc_fail("buffer_dereference() succeeded on error input");
211    }
212    a->refcnt = 2;
213    if (!buffer_dereference(&b, MDL)) {
214        atf_tc_fail("buffer_dereference() failed");
215    }
216    if (!buffer_dereference(&a, MDL)) {
217        atf_tc_fail("buffer_dereference() failed");
218    }
219}
220
221ATF_TC(data_string_forget);
222
223ATF_TC_HEAD(data_string_forget, tc) {
224    atf_tc_set_md_var(tc, "descr", "data_string_forget basic test");
225}
226
227ATF_TC_BODY(data_string_forget, tc) {
228    struct buffer *buf;
229    struct data_string a;
230    const char *str = "Lorem ipsum dolor sit amet turpis duis.";
231
232    /*
233     * Create the string we want to forget.
234     */
235    memset(&a, 0, sizeof(a));
236    a.len = strlen(str);
237    buf = NULL;
238    if (!buffer_allocate(&buf, a.len, MDL)) {
239        atf_tc_fail("out of memory");
240    }
241    if (!buffer_reference(&a.buffer, buf, MDL)) {
242        atf_tc_fail("buffer_reference() failed");
243    }
244    a.data = a.buffer->data;
245    memcpy(a.buffer->data, str, a.len);
246
247    /*
248     * Forget and confirm we've forgotten.
249     */
250    data_string_forget(&a, MDL);
251
252    if (a.len != 0) {
253        atf_tc_fail("incorrect length");
254    }
255
256    if (a.data != NULL) {
257        atf_tc_fail("incorrect data");
258    }
259    if (a.terminated) {
260        atf_tc_fail("incorrect terminated");
261    }
262    if (a.buffer != NULL) {
263        atf_tc_fail("incorrect buffer");
264    }
265    if (buf->refcnt != 1) {
266        atf_tc_fail("too many references to buf");
267    }
268
269    /*
270     * Clean up buffer.
271     */
272    if (!buffer_dereference(&buf, MDL)) {
273        atf_tc_fail("buffer_reference() failed");
274    }
275}
276
277ATF_TC(data_string_forget_nobuf);
278
279ATF_TC_HEAD(data_string_forget_nobuf, tc) {
280    atf_tc_set_md_var(tc, "descr", "data_string_forget test, "
281                      "data_string without buffer");
282}
283
284ATF_TC_BODY(data_string_forget_nobuf, tc) {
285    struct data_string a;
286    const char *str = "Lorem ipsum dolor sit amet massa nunc.";
287
288    /*
289     * Create the string we want to forget.
290     */
291    memset(&a, 0, sizeof(a));
292    a.len = strlen(str);
293    a.data = (const unsigned char *)str;
294    a.terminated = 1;
295
296    /*
297     * Forget and confirm we've forgotten.
298     */
299    data_string_forget(&a, MDL);
300
301    if (a.len != 0) {
302        atf_tc_fail("incorrect length");
303    }
304    if (a.data != NULL) {
305        atf_tc_fail("incorrect data");
306    }
307    if (a.terminated) {
308        atf_tc_fail("incorrect terminated");
309    }
310    if (a.buffer != NULL) {
311        atf_tc_fail("incorrect buffer");
312    }
313}
314
315ATF_TC(data_string_copy);
316
317ATF_TC_HEAD(data_string_copy, tc) {
318    atf_tc_set_md_var(tc, "descr", "data_string_copy basic test");
319}
320
321ATF_TC_BODY(data_string_copy, tc) {
322    struct data_string a, b;
323    const char *str = "Lorem ipsum dolor sit amet orci aliquam.";
324
325    /*
326     * Create the string we want to copy.
327         */
328    memset(&a, 0, sizeof(a));
329    a.len = strlen(str);
330    if (!buffer_allocate(&a.buffer, a.len, MDL)) {
331        atf_tc_fail("out of memory");
332    }
333    a.data = a.buffer->data;
334    memcpy(a.buffer->data, str, a.len);
335
336    /*
337     * Copy the string, and confirm it works.
338     */
339    memset(&b, 0, sizeof(b));
340    data_string_copy(&b, &a, MDL);
341
342    if (b.len != a.len) {
343        atf_tc_fail("incorrect length");
344    }
345    if (b.data != a.data) {
346        atf_tc_fail("incorrect data");
347    }
348    if (b.terminated != a.terminated) {
349        atf_tc_fail("incorrect terminated");
350    }
351    if (b.buffer != a.buffer) {
352        atf_tc_fail("incorrect buffer");
353    }
354
355    /*
356     * Clean up.
357     */
358    data_string_forget(&b, MDL);
359    data_string_forget(&a, MDL);
360}
361
362ATF_TC(data_string_copy_nobuf);
363
364ATF_TC_HEAD(data_string_copy_nobuf, tc) {
365    atf_tc_set_md_var(tc, "descr", "data_string_copy test, "
366                      "data_string without buffer");
367}
368
369ATF_TC_BODY(data_string_copy_nobuf, tc) {
370    struct data_string a, b;
371    const char *str = "Lorem ipsum dolor sit amet cras amet.";
372
373    /*
374     * Create the string we want to copy.
375     */
376    memset(&a, 0, sizeof(a));
377    a.len = strlen(str);
378    a.data = (const unsigned char *)str;
379    a.terminated = 1;
380
381    /*
382     * Copy the string, and confirm it works.
383     */
384    memset(&b, 0, sizeof(b));
385    data_string_copy(&b, &a, MDL);
386
387    if (b.len != a.len) {
388        atf_tc_fail("incorrect length");
389    }
390    if (b.data != a.data) {
391        atf_tc_fail("incorrect data");
392    }
393    if (b.terminated != a.terminated) {
394        atf_tc_fail("incorrect terminated");
395    }
396    if (b.buffer != a.buffer) {
397        atf_tc_fail("incorrect buffer");
398    }
399
400    /*
401     * Clean up.
402     */
403    data_string_forget(&b, MDL);
404    data_string_forget(&a, MDL);
405
406}
407
408
409ATF_TC(data_string_new);
410
411ATF_TC_HEAD(data_string_new, tc) {
412    atf_tc_set_md_var(tc, "descr", "data_string_new test, "
413                      "exercises data_string_new function");
414}
415
416ATF_TC_BODY(data_string_new, tc) {
417    struct data_string new_string;
418    const char *src = "Really? Latin? ... geeks";
419    int len_arg = 0;
420    const char *error;
421
422    /* Case 1: Call with an invalid data_string pointer, should fail */
423    if (data_string_new(NULL, src, len_arg, MDL)) {
424        atf_tc_fail("case 1: call should have failed");
425    }
426
427    /* Case 2: Passing in NULL src should fail */
428    if (data_string_new(&new_string, NULL, 10, MDL)) {
429        atf_tc_fail("case 2: did not return success");
430    }
431
432    /* Case 3: Call with valid params, length includes NULL */
433    len_arg = strlen(src) + 1;
434    if (data_string_new(&new_string, src, len_arg, MDL) == 0) {
435        atf_tc_fail("case 3: did not return success");
436    }
437
438    error = checkString(&new_string, src);
439    ATF_REQUIRE_MSG((error == NULL), "case 3: %s", error);
440    data_string_forget(&new_string, MDL);
441
442
443    /* Case 4: Call with valid params, length does not include NULL */
444    len_arg = 7;
445    if (data_string_new(&new_string, src, len_arg, MDL) == 0) {
446        atf_tc_fail("case 4: did not return success");
447    }
448
449    error = checkString(&new_string, "Really?");
450    ATF_REQUIRE_MSG((error == NULL), "case 4: %s", error);
451    data_string_forget(&new_string, MDL);
452
453
454    /* Case 5: Call with valid params, source string is "" */
455    len_arg = 0;
456    if (data_string_new(&new_string, "", len_arg, MDL) == 0) {
457        atf_tc_fail("case 5: did not return success");
458    }
459
460    error = checkString(&new_string, "");
461    ATF_REQUIRE_MSG((error == NULL), "case 4: %s", error);
462    data_string_forget(&new_string, MDL);
463
464
465}
466
467/* Helper function which tests validity of a data_string
468*
469* Verifies that the given data_string contains a null-terminated string
470* equal to a given string.
471*
472* \param string data_string to test
473* \param src text content string should contain
474* \return returns NULL if data_string is validate or an error message
475* describing why it is invalid
476*/
477const char* checkString (struct data_string* string,
478    const char* src) {
479    int src_len = strlen(src);
480
481    if (string->buffer == NULL) {
482        return ("buffer is NULL");
483    }
484
485    if (string->data != string->buffer->data) {
486        return ("data not set to buffer->data");
487    }
488
489    if (string->len != src_len) {
490        return ("len is wrong ");
491    }
492
493    if (string->terminated != 1)  {
494        return ("terminated flag not set");
495    }
496
497    if (memcmp(string->data, src, src_len + 1)) {
498        return ("data content wrong");
499    }
500
501    return (NULL);
502}
503
504ATF_TC(data_string_terminate);
505
506ATF_TC_HEAD(data_string_terminate, tc) {
507    atf_tc_set_md_var(tc, "descr", "data_string_terminate test, "
508                      "exercises data_string_terminate function");
509}
510
511ATF_TC_BODY(data_string_terminate, tc) {
512    struct data_string new_string, copy_string;
513    const char *src = "Boring test string";
514
515    /* Case 1: Call with an already terminated string.  The
516     * original structure shouldn't be touched.
517     */
518    memset(&new_string, 0, sizeof(new_string));
519    memset(&copy_string, 0, sizeof(copy_string));
520    if (data_string_new(&new_string, src, strlen(src), MDL) == 0) {
521	atf_tc_fail("Case 1: unable to create new string");
522    }
523    memcpy(&copy_string, &new_string, sizeof(new_string));
524    if (data_string_terminate(&new_string, MDL) == 0) {
525	atf_tc_fail("Case 1: unable to terminate string");
526    }
527    if (memcmp(&copy_string, &new_string, sizeof(new_string)) != 0) {
528	atf_tc_fail("Case 1: structure modified");
529    }
530
531    /* Case 2: Call with an unterminated string.  The
532     * original structure should be modified with a pointer
533     * to new memory for the string.
534     */
535    /* clear the termination flag, and shrink the string */
536    new_string.terminated = 0;
537    new_string.len -= 2;
538    memcpy(&copy_string, &new_string, sizeof(new_string));
539
540    if (data_string_terminate(&new_string, MDL) == 0) {
541	atf_tc_fail("Case 2: unable to terminate string");
542    }
543
544    /* We expect the same string but in a differnet block of memory */
545    if ((new_string.terminated == 0) ||
546	(&new_string.buffer == &copy_string.buffer) ||
547	(new_string.len != copy_string.len) ||
548	memcmp(new_string.data, src, new_string.len) ||
549	new_string.data[new_string.len] != 0) {
550	atf_tc_fail("Case 2: structure not modified correctly");
551    }
552
553    /* get rid of the string, no need to get rid of copy as the
554     * string memory was freed during the terminate call */
555    data_string_forget(&new_string, MDL);
556}
557
558void checkBuffer(size_t test_size, const char *file, int line) {
559    char *buf;
560    size_t max_size;
561    /* Determine the maximum size we may have
562     * Depending on configuration options we may be adding some
563     * space to the allocated buffer for debugging purposes
564     * so remove that as well.
565     */
566    max_size = ((size_t)-1) - DMDSIZE;
567
568    if (test_size > max_size) {
569	atf_tc_skip("Test size greater than max size, %zu", test_size);
570	return;
571    }
572
573    /* We allocate the buffer and then try to set the last character
574     * to a known value.
575     */
576    buf = dmalloc(test_size, file, line);
577    if (buf != NULL) {
578	buf[test_size - 1] = 1;
579	if (buf[test_size - 1] != 1)
580	    atf_tc_fail("Value mismatch for index %zu", test_size);
581	dfree(buf, file, line);
582    } else {
583	atf_tc_skip("Unable to allocate memory %zu", test_size);
584    }
585}
586
587#if 0
588/* The max test presents some issues for some systems,
589 * leave it out for now
590 */
591ATF_TC(dmalloc_max32);
592
593ATF_TC_HEAD(dmalloc_max32, tc) {
594    atf_tc_set_md_var(tc, "descr", "dmalloc_max32 test, "
595		      "dmalloc 0xFFFFFFFF");
596}
597ATF_TC_BODY(dmalloc_max32, tc) {
598    checkBuffer(0XFFFFFFFF, MDL);
599}
600#endif
601
602ATF_TC(dmalloc_med1);
603
604ATF_TC_HEAD(dmalloc_med1, tc) {
605    atf_tc_set_md_var(tc, "descr", "dmalloc_med1 test, "
606		      "dmalloc 0x80000000,");
607}
608ATF_TC_BODY(dmalloc_med1, tc) {
609    checkBuffer(0x80000000, MDL);
610}
611
612ATF_TC(dmalloc_med2);
613
614ATF_TC_HEAD(dmalloc_med2, tc) {
615    atf_tc_set_md_var(tc, "descr", "dmalloc_med2 test, "
616		      "dmalloc 0x7FFFFFFF, ");
617}
618ATF_TC_BODY(dmalloc_med2, tc) {
619    checkBuffer(0x7FFFFFFF,  MDL);
620}
621
622ATF_TC(dmalloc_med3);
623
624ATF_TC_HEAD(dmalloc_med3, tc) {
625    atf_tc_set_md_var(tc, "descr", "dmalloc_med3 test, "
626		      "dmalloc 0x10000000,");
627}
628ATF_TC_BODY(dmalloc_med3, tc) {
629    checkBuffer(0x10000000, MDL);
630}
631
632ATF_TC(dmalloc_small);
633
634ATF_TC_HEAD(dmalloc_small, tc) {
635    atf_tc_set_md_var(tc, "descr", "dmalloc_small test, "
636		      "dmalloc 0x0FFFFFFF");
637}
638ATF_TC_BODY(dmalloc_small, tc) {
639    checkBuffer(0X0FFFFFFF, MDL);
640}
641
642ATF_TP_ADD_TCS(tp)
643{
644    ATF_TP_ADD_TC(tp, buffer_allocate);
645    ATF_TP_ADD_TC(tp, buffer_reference);
646    ATF_TP_ADD_TC(tp, buffer_dereference);
647    ATF_TP_ADD_TC(tp, data_string_forget);
648    ATF_TP_ADD_TC(tp, data_string_forget_nobuf);
649    ATF_TP_ADD_TC(tp, data_string_copy);
650    ATF_TP_ADD_TC(tp, data_string_copy_nobuf);
651    ATF_TP_ADD_TC(tp, data_string_new);
652    ATF_TP_ADD_TC(tp, data_string_terminate);
653#if 0
654    ATF_TP_ADD_TC(tp, dmalloc_max32);
655#endif
656    ATF_TP_ADD_TC(tp, dmalloc_med1);
657    ATF_TP_ADD_TC(tp, dmalloc_med2);
658    ATF_TP_ADD_TC(tp, dmalloc_med3);
659    ATF_TP_ADD_TC(tp, dmalloc_small);
660
661    return (atf_no_error());
662}
663