xref: /openbsd-src/usr.sbin/unbound/testcode/unitregional.c (revision b0dfc31be27198e43ddd415778a6a190eb205f66)
1712b2f30Ssthen /*
2712b2f30Ssthen  * testcode/unitregional.c - unit test for regional allocator.
3712b2f30Ssthen  *
4712b2f30Ssthen  * Copyright (c) 2010, NLnet Labs. All rights reserved.
5712b2f30Ssthen  *
6712b2f30Ssthen  * This software is open source.
7712b2f30Ssthen  *
8712b2f30Ssthen  * Redistribution and use in source and binary forms, with or without
9712b2f30Ssthen  * modification, are permitted provided that the following conditions
10712b2f30Ssthen  * are met:
11712b2f30Ssthen  *
12712b2f30Ssthen  * Redistributions of source code must retain the above copyright notice,
13712b2f30Ssthen  * this list of conditions and the following disclaimer.
14712b2f30Ssthen  *
15712b2f30Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16712b2f30Ssthen  * this list of conditions and the following disclaimer in the documentation
17712b2f30Ssthen  * and/or other materials provided with the distribution.
18712b2f30Ssthen  *
19712b2f30Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20712b2f30Ssthen  * be used to endorse or promote products derived from this software without
21712b2f30Ssthen  * specific prior written permission.
22712b2f30Ssthen  *
23712b2f30Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24712b2f30Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25712b2f30Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26712b2f30Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27712b2f30Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28712b2f30Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29712b2f30Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30712b2f30Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31712b2f30Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32712b2f30Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33712b2f30Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34712b2f30Ssthen  *
35712b2f30Ssthen  */
36712b2f30Ssthen /**
37712b2f30Ssthen  * \file
38712b2f30Ssthen  * Tests the regional special purpose allocator.
39712b2f30Ssthen  */
40712b2f30Ssthen 
41712b2f30Ssthen #include "config.h"
42712b2f30Ssthen #include "testcode/unitmain.h"
43712b2f30Ssthen #include "util/log.h"
44712b2f30Ssthen #include "util/regional.h"
45712b2f30Ssthen 
46712b2f30Ssthen /** test regional corner cases, zero, one, end of structure */
47712b2f30Ssthen static void
corner_cases(struct regional * r)48712b2f30Ssthen corner_cases(struct regional* r)
49712b2f30Ssthen {
50712b2f30Ssthen 	size_t s; /* shadow count of allocated memory */
51712b2f30Ssthen 	void* a;
52712b2f30Ssthen 	size_t minsize = sizeof(uint64_t);
53*b0dfc31bSsthen #ifndef UNBOUND_ALLOC_NONREGIONAL
54712b2f30Ssthen 	size_t mysize;
55*b0dfc31bSsthen #endif
56712b2f30Ssthen 	char* str;
57712b2f30Ssthen 	unit_assert(r);
58712b2f30Ssthen 	/* alloc cases:
59712b2f30Ssthen 	 * 0, 1, 2.
60712b2f30Ssthen 	 * smaller than LARGE_OBJECT_SIZE.
61712b2f30Ssthen 	 * smaller but does not fit in remainder in regional.
62712b2f30Ssthen 	 * smaller but exactly fits in remainder of regional.
63712b2f30Ssthen 	 * size is remainder of regional - 8.
64712b2f30Ssthen 	 * size is remainder of regional + 8.
65712b2f30Ssthen 	 * larger than LARGE_OBJECT_SIZE.
66712b2f30Ssthen 	 */
67712b2f30Ssthen 	s = sizeof(struct regional);
68712b2f30Ssthen 	unit_assert((s % minsize) == 0);
69712b2f30Ssthen 	unit_assert(r->available == r->first_size - s);
70712b2f30Ssthen 	unit_assert(r->large_list == NULL);
71712b2f30Ssthen 	unit_assert(r->next == NULL);
72712b2f30Ssthen 
73712b2f30Ssthen 	/* Note an alloc of 0 gets a pointer to current last
74712b2f30Ssthen 	 * position (where you should then use 0 bytes) */
75712b2f30Ssthen 	a = regional_alloc(r, 0);
76712b2f30Ssthen 	unit_assert(a);
77712b2f30Ssthen 	s+=0;
78712b2f30Ssthen 	unit_assert(r->available == r->first_size - s);
79712b2f30Ssthen 
80*b0dfc31bSsthen #ifndef UNBOUND_ALLOC_NONREGIONAL
81712b2f30Ssthen 	a = regional_alloc(r, 1);
82712b2f30Ssthen 	unit_assert(a);
83712b2f30Ssthen 	memset(a, 0x42, 1);
84712b2f30Ssthen 	s+=minsize;
85712b2f30Ssthen 	unit_assert(r->available == r->first_size - s);
86712b2f30Ssthen 
87712b2f30Ssthen 	a = regional_alloc(r, 2);
88712b2f30Ssthen 	unit_assert(a);
89712b2f30Ssthen 	memset(a, 0x42, 2);
90712b2f30Ssthen 	s+=minsize;
91712b2f30Ssthen 	unit_assert(r->available == r->first_size - s);
92712b2f30Ssthen 
93712b2f30Ssthen 	a = regional_alloc(r, 128);
94712b2f30Ssthen 	unit_assert(a);
95712b2f30Ssthen 	memset(a, 0x42, 128);
96712b2f30Ssthen 	s+=128;
97712b2f30Ssthen 	unit_assert(r->available == r->first_size - s);
98712b2f30Ssthen 
99712b2f30Ssthen 	unit_assert(r->large_list == NULL);
100712b2f30Ssthen 	a = regional_alloc(r, 10240);
101712b2f30Ssthen 	unit_assert(a);
102712b2f30Ssthen 	unit_assert(r->large_list != NULL);
103712b2f30Ssthen 	memset(a, 0x42, 10240);
104712b2f30Ssthen 	/* s does not change */
105712b2f30Ssthen 	unit_assert(r->available == r->first_size - s);
106712b2f30Ssthen 	unit_assert(r->total_large == 10240+minsize);
107712b2f30Ssthen 
108712b2f30Ssthen 	/* go towards the end of the current chunk */
109712b2f30Ssthen 	while(r->available > 1024) {
110712b2f30Ssthen 		a = regional_alloc(r, 1024);
111712b2f30Ssthen 		unit_assert(a);
112712b2f30Ssthen 		memset(a, 0x42, 1024);
113712b2f30Ssthen 		s += 1024;
114712b2f30Ssthen 		unit_assert(r->available == r->first_size - s);
115712b2f30Ssthen 	}
116712b2f30Ssthen 
117712b2f30Ssthen 	unit_assert(r->next == NULL);
118712b2f30Ssthen 	mysize = 1280; /* does not fit in current chunk */
119712b2f30Ssthen 	a = regional_alloc(r, mysize);
120712b2f30Ssthen 	memset(a, 0x42, mysize);
121712b2f30Ssthen 	unit_assert(r->next != NULL);
122712b2f30Ssthen 	unit_assert(a);
123712b2f30Ssthen 
124712b2f30Ssthen 	/* go towards the end of the current chunk */
125712b2f30Ssthen 	while(r->available > 864) {
126712b2f30Ssthen 		a = regional_alloc(r, 864);
127712b2f30Ssthen 		unit_assert(a);
128712b2f30Ssthen 		memset(a, 0x42, 864);
129712b2f30Ssthen 		s += 864;
130712b2f30Ssthen 	}
131712b2f30Ssthen 
132712b2f30Ssthen 	mysize = r->available; /* exactly fits */
133712b2f30Ssthen 	a = regional_alloc(r, mysize);
134712b2f30Ssthen 	memset(a, 0x42, mysize);
135712b2f30Ssthen 	unit_assert(a);
136712b2f30Ssthen 	unit_assert(r->available == 0); /* implementation does not go ahead*/
137712b2f30Ssthen 
138712b2f30Ssthen 	a = regional_alloc(r, 8192); /* another large allocation */
139712b2f30Ssthen 	unit_assert(a);
140712b2f30Ssthen 	memset(a, 0x42, 8192);
141712b2f30Ssthen 	unit_assert(r->available == 0);
142712b2f30Ssthen 	unit_assert(r->total_large == 10240 + 8192 + 2*minsize);
143712b2f30Ssthen 
144712b2f30Ssthen 	a = regional_alloc(r, 32); /* make new chunk */
145712b2f30Ssthen 	unit_assert(a);
146712b2f30Ssthen 	memset(a, 0x42, 32);
147712b2f30Ssthen 	unit_assert(r->available > 0);
148712b2f30Ssthen 	unit_assert(r->total_large == 10240 + 8192 + 2*minsize);
149712b2f30Ssthen 
150712b2f30Ssthen 	/* go towards the end of the current chunk */
151712b2f30Ssthen 	while(r->available > 1320) {
152712b2f30Ssthen 		a = regional_alloc(r, 1320);
153712b2f30Ssthen 		unit_assert(a);
154712b2f30Ssthen 		memset(a, 0x42, 1320);
155712b2f30Ssthen 		s += 1320;
156712b2f30Ssthen 	}
157712b2f30Ssthen 
158712b2f30Ssthen 	mysize = r->available + 8; /* exact + 8 ; does not fit */
159712b2f30Ssthen 	a = regional_alloc(r, mysize);
160712b2f30Ssthen 	memset(a, 0x42, mysize);
161712b2f30Ssthen 	unit_assert(a);
162712b2f30Ssthen 	unit_assert(r->available > 0); /* new chunk */
163712b2f30Ssthen 
164712b2f30Ssthen 	/* go towards the end of the current chunk */
165712b2f30Ssthen 	while(r->available > 1480) {
166712b2f30Ssthen 		a = regional_alloc(r, 1480);
167712b2f30Ssthen 		unit_assert(a);
168712b2f30Ssthen 		memset(a, 0x42, 1480);
169712b2f30Ssthen 		s += 1480;
170712b2f30Ssthen 	}
171712b2f30Ssthen 
172712b2f30Ssthen 	mysize = r->available - 8; /* exact - 8 ; fits. */
173712b2f30Ssthen 	a = regional_alloc(r, mysize);
174712b2f30Ssthen 	memset(a, 0x42, mysize);
175712b2f30Ssthen 	unit_assert(a);
176712b2f30Ssthen 	unit_assert(r->available == 8);
177*b0dfc31bSsthen #endif /* UNBOUND_ALLOC_NONREGIONAL */
178712b2f30Ssthen 
179712b2f30Ssthen 	/* test if really copied over */
180712b2f30Ssthen 	str = "test12345";
181712b2f30Ssthen 	a = regional_alloc_init(r, str, 8);
182712b2f30Ssthen 	unit_assert(a);
183712b2f30Ssthen 	unit_assert(memcmp(a, str, 8) == 0);
184712b2f30Ssthen 
185712b2f30Ssthen 	/* test if really zeroed */
186712b2f30Ssthen 	a = regional_alloc_zero(r, 32);
187712b2f30Ssthen 	str="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
188712b2f30Ssthen 	unit_assert(a);
189712b2f30Ssthen 	unit_assert(memcmp(a, str, 32) == 0);
190712b2f30Ssthen 
191712b2f30Ssthen 	/* test if copied over (and null byte) */
192712b2f30Ssthen 	str = "an interesting string";
193712b2f30Ssthen 	a = regional_strdup(r, str);
194712b2f30Ssthen 	unit_assert(a);
195712b2f30Ssthen 	unit_assert(memcmp(a, str, strlen(str)+1) == 0);
196712b2f30Ssthen 
197712b2f30Ssthen 	regional_free_all(r);
198712b2f30Ssthen }
199712b2f30Ssthen 
200712b2f30Ssthen /** test specific cases */
201712b2f30Ssthen static void
specific_cases(void)202712b2f30Ssthen specific_cases(void)
203712b2f30Ssthen {
204712b2f30Ssthen 	struct regional* r = regional_create();
205712b2f30Ssthen 	corner_cases(r);
206712b2f30Ssthen 	regional_destroy(r);
207712b2f30Ssthen 	r = regional_create_custom(2048); /* a small regional */
208712b2f30Ssthen 	unit_assert(r->first_size == 2048);
209712b2f30Ssthen 	unit_assert(regional_get_mem(r) == 2048);
210712b2f30Ssthen 	corner_cases(r);
211712b2f30Ssthen 	unit_assert(regional_get_mem(r) == 2048);
212712b2f30Ssthen 	regional_destroy(r);
213712b2f30Ssthen }
214712b2f30Ssthen 
215712b2f30Ssthen /** put random stuff in a region and free it */
216712b2f30Ssthen static void
burden_test(size_t max)217712b2f30Ssthen burden_test(size_t max)
218712b2f30Ssthen {
219712b2f30Ssthen 	size_t get;
220712b2f30Ssthen 	void* a;
221712b2f30Ssthen 	int i;
222712b2f30Ssthen 	struct regional* r = regional_create_custom(2048);
223712b2f30Ssthen 	for(i=0; i<1000; i++) {
224712b2f30Ssthen 		get = random() % max;
225712b2f30Ssthen 		a = regional_alloc(r, get);
226712b2f30Ssthen 		unit_assert(a);
227712b2f30Ssthen 		memset(a, 0x54, get);
228712b2f30Ssthen 	}
229712b2f30Ssthen 	regional_free_all(r);
230712b2f30Ssthen 	regional_destroy(r);
231712b2f30Ssthen }
232712b2f30Ssthen 
233712b2f30Ssthen /** randomly allocate stuff */
234712b2f30Ssthen static void
random_burden(void)235712b2f30Ssthen random_burden(void)
236712b2f30Ssthen {
237712b2f30Ssthen 	size_t max_alloc = 2048 + 128; /* small chance of LARGE */
238712b2f30Ssthen 	int i;
239712b2f30Ssthen 	for(i=0; i<100; i++)
240712b2f30Ssthen 		burden_test(max_alloc);
241712b2f30Ssthen }
242712b2f30Ssthen 
regional_test(void)243712b2f30Ssthen void regional_test(void)
244712b2f30Ssthen {
245712b2f30Ssthen 	unit_show_feature("regional");
246712b2f30Ssthen 	specific_cases();
247712b2f30Ssthen 	random_burden();
248712b2f30Ssthen }
249