1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 #include <config.h>
13
14 #if HAVE_CMOCKA
15
16 #include <stdarg.h>
17 #include <stddef.h>
18 #include <setjmp.h>
19
20 #include <fcntl.h>
21 #include <sched.h> /* IWYU pragma: keep */
22 #include <stdlib.h>
23 #include <unistd.h>
24
25 #define UNIT_TESTING
26 #include <cmocka.h>
27
28 #include <isc/mem.h>
29 #include <isc/print.h>
30 #include <isc/result.h>
31 #include <isc/stdio.h>
32 #include <isc/util.h>
33
34 #include "isctest.h"
35
36 static int
_setup(void ** state)37 _setup(void **state) {
38 isc_result_t result;
39
40 UNUSED(state);
41
42 result = isc_test_begin(NULL, true, 0);
43 assert_int_equal(result, ISC_R_SUCCESS);
44
45 return (0);
46 }
47
48 static int
_teardown(void ** state)49 _teardown(void **state) {
50 UNUSED(state);
51
52 isc_test_end();
53
54 return (0);
55 }
56
57 static void *
default_memalloc(void * arg,size_t size)58 default_memalloc(void *arg, size_t size) {
59 UNUSED(arg);
60 if (size == 0U) {
61 size = 1;
62 }
63 /* cppcheck-suppress leakNoVarFunctionCall */
64 return (malloc(size));
65 }
66
67 static void
default_memfree(void * arg,void * ptr)68 default_memfree(void *arg, void *ptr) {
69 UNUSED(arg);
70 free(ptr);
71 }
72
73 #define MP1_FREEMAX 10
74 #define MP1_FILLCNT 10
75 #define MP1_MAXALLOC 30
76
77 #define MP2_FREEMAX 25
78 #define MP2_FILLCNT 25
79
80 /* general memory system tests */
81 static void
isc_mem_test(void ** state)82 isc_mem_test(void **state) {
83 isc_result_t result;
84 void *items1[50];
85 void *items2[50];
86 void *tmp;
87 isc_mem_t *localmctx = NULL;
88 isc_mempool_t *mp1 = NULL, *mp2 = NULL;
89 unsigned int i, j;
90 int rval;
91
92 UNUSED(state);
93
94 result = isc_mem_create(0, 0, &localmctx);
95 assert_int_equal(result, ISC_R_SUCCESS);
96
97 result = isc_mempool_create(localmctx, 24, &mp1);
98 assert_int_equal(result, ISC_R_SUCCESS);
99
100 result = isc_mempool_create(localmctx, 31, &mp2);
101 assert_int_equal(result, ISC_R_SUCCESS);
102
103 isc_mempool_setfreemax(mp1, MP1_FREEMAX);
104 isc_mempool_setfillcount(mp1, MP1_FILLCNT);
105 isc_mempool_setmaxalloc(mp1, MP1_MAXALLOC);
106
107 /*
108 * Allocate MP1_MAXALLOC items from the pool. This is our max.
109 */
110 for (i = 0; i < MP1_MAXALLOC; i++) {
111 items1[i] = isc_mempool_get(mp1);
112 assert_non_null(items1[i]);
113 }
114
115 /*
116 * Try to allocate one more. This should fail.
117 */
118 tmp = isc_mempool_get(mp1);
119 assert_null(tmp);
120
121 /*
122 * Free the first 11 items. Verify that there are 10 free items on
123 * the free list (which is our max).
124 */
125 for (i = 0; i < 11; i++) {
126 isc_mempool_put(mp1, items1[i]);
127 items1[i] = NULL;
128 }
129
130 rval = isc_mempool_getfreecount(mp1);
131 assert_int_equal(rval, 10);
132
133 rval = isc_mempool_getallocated(mp1);
134 assert_int_equal(rval, 19);
135
136 /*
137 * Now, beat up on mp2 for a while. Allocate 50 items, then free
138 * them, then allocate 50 more, etc.
139 */
140
141 isc_mempool_setfreemax(mp2, 25);
142 isc_mempool_setfillcount(mp2, 25);
143
144 for (j = 0; j < 500000; j++) {
145 for (i = 0; i < 50; i++) {
146 items2[i] = isc_mempool_get(mp2);
147 assert_non_null(items2[i]);
148 }
149 for (i = 0; i < 50; i++) {
150 isc_mempool_put(mp2, items2[i]);
151 items2[i] = NULL;
152 }
153 }
154
155 /*
156 * Free all the other items and blow away this pool.
157 */
158 for (i = 11; i < MP1_MAXALLOC; i++) {
159 isc_mempool_put(mp1, items1[i]);
160 items1[i] = NULL;
161 }
162
163 isc_mempool_destroy(&mp1);
164 isc_mempool_destroy(&mp2);
165
166 isc_mem_destroy(&localmctx);
167
168 result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
169 NULL, &localmctx, ISC_MEMFLAG_INTERNAL);
170 assert_int_equal(result, ISC_R_SUCCESS);
171
172 result = isc_mempool_create(localmctx, 2, &mp1);
173 assert_int_equal(result, ISC_R_SUCCESS);
174
175 tmp = isc_mempool_get(mp1);
176 assert_non_null(tmp);
177
178 isc_mempool_put(mp1, tmp);
179
180 isc_mempool_destroy(&mp1);
181
182 isc_mem_destroy(&localmctx);
183
184 }
185
186 /* test TotalUse calculation */
187 static void
isc_mem_total_test(void ** state)188 isc_mem_total_test(void **state) {
189 isc_result_t result;
190 isc_mem_t *mctx2 = NULL;
191 size_t before, after;
192 ssize_t diff;
193 int i;
194
195 UNUSED(state);
196
197 /* Local alloc, free */
198 mctx2 = NULL;
199 result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
200 NULL, &mctx2, 0);
201 if (result != ISC_R_SUCCESS) {
202 goto out;
203 }
204
205 before = isc_mem_total(mctx2);
206
207 for (i = 0; i < 100000; i++) {
208 void *ptr;
209
210 ptr = isc_mem_allocate(mctx2, 2048);
211 isc_mem_free(mctx2, ptr);
212 }
213
214 after = isc_mem_total(mctx2);
215 diff = after - before;
216
217 /* 2048 +8 bytes extra for size_info */
218 assert_int_equal(diff, (2048 + 8) * 100000);
219
220 /* ISC_MEMFLAG_INTERNAL */
221
222 before = isc_mem_total(mctx);
223
224 for (i = 0; i < 100000; i++) {
225 void *ptr;
226
227 ptr = isc_mem_allocate(mctx, 2048);
228 isc_mem_free(mctx, ptr);
229 }
230
231 after = isc_mem_total(mctx);
232 diff = after - before;
233
234 /* 2048 +8 bytes extra for size_info */
235 assert_int_equal(diff, (2048 + 8) * 100000);
236
237 out:
238 if (mctx2 != NULL) {
239 isc_mem_destroy(&mctx2);
240 }
241
242 }
243
244 /* test InUse calculation */
245 static void
isc_mem_inuse_test(void ** state)246 isc_mem_inuse_test(void **state) {
247 isc_result_t result;
248 isc_mem_t *mctx2 = NULL;
249 size_t before, after;
250 ssize_t diff;
251 void *ptr;
252
253 UNUSED(state);
254
255 mctx2 = NULL;
256 result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
257 NULL, &mctx2, 0);
258 if (result != ISC_R_SUCCESS) {
259 goto out;
260 }
261
262 before = isc_mem_inuse(mctx2);
263 ptr = isc_mem_allocate(mctx2, 1024000);
264 isc_mem_free(mctx2, ptr);
265 after = isc_mem_inuse(mctx2);
266
267 diff = after - before;
268
269 assert_int_equal(diff, 0);
270
271 out:
272 if (mctx2 != NULL) {
273 isc_mem_destroy(&mctx2);
274 }
275
276 }
277
278 /*
279 * Main
280 */
281
282 int
main(void)283 main(void) {
284 const struct CMUnitTest tests[] = {
285 cmocka_unit_test_setup_teardown(isc_mem_test,
286 _setup, _teardown),
287 cmocka_unit_test_setup_teardown(isc_mem_total_test,
288 _setup, _teardown),
289 cmocka_unit_test_setup_teardown(isc_mem_inuse_test,
290 _setup, _teardown),
291 };
292
293 return (cmocka_run_group_tests(tests, NULL, NULL));
294 }
295
296 #else /* HAVE_CMOCKA */
297
298 #include <stdio.h>
299
300 int
main(void)301 main(void) {
302 printf("1..0 # Skipped: cmocka not available\n");
303 return (0);
304
305 }
306
307 #endif
308