buffer_test.c revision 1.3 1 /* $NetBSD: buffer_test.c,v 1.3 2025/01/26 16:25:49 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 #include <fcntl.h>
17 #include <inttypes.h>
18 #include <limits.h>
19 #include <sched.h> /* IWYU pragma: keep */
20 #include <setjmp.h>
21 #include <stdarg.h>
22 #include <stdbool.h>
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #define UNIT_TESTING
29 #include <cmocka.h>
30
31 #include <isc/buffer.h>
32 #include <isc/region.h>
33 #include <isc/result.h>
34 #include <isc/types.h>
35 #include <isc/util.h>
36
37 #include <tests/isc.h>
38
39 /* reserve space in dynamic buffers */
40 ISC_RUN_TEST_IMPL(isc_buffer_reserve) {
41 isc_result_t result;
42 isc_buffer_t *b;
43
44 UNUSED(state);
45
46 b = NULL;
47 isc_buffer_allocate(mctx, &b, ISC_BUFFER_INCR);
48 assert_int_equal(b->length, ISC_BUFFER_INCR);
49
50 /*
51 * 512 bytes should already be available, so this call does
52 * nothing.
53 */
54 result = isc_buffer_reserve(b, 512);
55 assert_int_equal(result, ISC_R_SUCCESS);
56 assert_non_null(b);
57 assert_int_equal(b->length, ISC_BUFFER_INCR);
58
59 /*
60 * This call should grow it to 1536 bytes as only 1024 bytes are
61 * available in the buffer.
62 */
63 result = isc_buffer_reserve(b, 1025);
64 assert_int_equal(result, ISC_R_SUCCESS);
65 assert_non_null(b);
66 assert_int_equal(b->length, 3 * ISC_BUFFER_INCR);
67
68 /*
69 * 1536 bytes should already be available, so this call does
70 * nothing.
71 */
72 result = isc_buffer_reserve(b, 1500);
73 assert_int_equal(result, ISC_R_SUCCESS);
74 assert_non_null(b);
75 assert_int_equal(b->length, 3 * ISC_BUFFER_INCR);
76
77 /*
78 * This call should grow it to 4096 bytes as only 1536 bytes are
79 * available in the buffer.
80 */
81 result = isc_buffer_reserve(b, 3585);
82 assert_int_equal(result, ISC_R_SUCCESS);
83 assert_non_null(b);
84 assert_int_equal(b->length, 8 * ISC_BUFFER_INCR);
85
86 /* Consume some of the buffer so we can run the next test. */
87 isc_buffer_add(b, 4096);
88
89 /*
90 * This call should fail and leave buffer untouched.
91 */
92 result = isc_buffer_reserve(b, UINT_MAX);
93 assert_int_equal(result, ISC_R_NOMEMORY);
94 assert_non_null(b);
95 assert_int_equal(b->length, 8 * ISC_BUFFER_INCR);
96
97 isc_buffer_free(&b);
98 }
99
100 /* dynamic buffer automatic reallocation */
101 ISC_RUN_TEST_IMPL(isc_buffer_dynamic) {
102 isc_buffer_t *b;
103 size_t last_length = 10;
104 int i;
105
106 UNUSED(state);
107
108 b = NULL;
109 isc_buffer_allocate(mctx, &b, last_length);
110 assert_non_null(b);
111 assert_int_equal(b->length, last_length);
112
113 isc_buffer_putuint8(b, 1);
114
115 for (i = 0; i < 1000; i++) {
116 isc_buffer_putstr(b, "thisisa24charslongstring");
117 }
118 assert_true(b->length - last_length >= 1000 * 24);
119 last_length += 1000 * 24;
120
121 for (i = 0; i < 10000; i++) {
122 isc_buffer_putuint8(b, 1);
123 }
124
125 assert_true(b->length - last_length >= 10000 * 1);
126 last_length += 10000 * 1;
127
128 for (i = 0; i < 10000; i++) {
129 isc_buffer_putuint16(b, 1);
130 }
131
132 assert_true(b->length - last_length >= 10000 * 2);
133
134 for (i = 0; i < 10000; i++) {
135 isc_buffer_putuint32(b, 1);
136 }
137 assert_true(b->length - last_length >= 10000 * 4);
138
139 isc_buffer_free(&b);
140 }
141
142 /* copy a region into a buffer */
143 ISC_RUN_TEST_IMPL(isc_buffer_copyregion) {
144 unsigned char data[] = { 0x11, 0x22, 0x33, 0x44 };
145 isc_buffer_t *b = NULL;
146 isc_result_t result;
147
148 isc_region_t r = {
149 .base = data,
150 .length = sizeof(data),
151 };
152
153 UNUSED(state);
154
155 isc_buffer_allocate(mctx, &b, sizeof(data));
156
157 /*
158 * Fill originally allocated buffer space.
159 */
160 result = isc_buffer_copyregion(b, &r);
161 assert_int_equal(result, ISC_R_SUCCESS);
162
163 /*
164 * Appending should succeed.
165 */
166 result = isc_buffer_copyregion(b, &r);
167 assert_int_equal(result, ISC_R_SUCCESS);
168
169 isc_buffer_free(&b);
170 }
171
172 /* sprintf() into a buffer */
173 ISC_RUN_TEST_IMPL(isc_buffer_printf) {
174 unsigned int used, prev_used;
175 const char *empty_fmt;
176 isc_result_t result;
177 isc_buffer_t *b, sb;
178 char buf[8];
179
180 UNUSED(state);
181
182 /*
183 * Prepare a buffer with auto-reallocation enabled.
184 */
185 b = NULL;
186 isc_buffer_allocate(mctx, &b, 0);
187
188 /*
189 * Sanity check.
190 */
191 result = isc_buffer_printf(b, "foo");
192 assert_int_equal(result, ISC_R_SUCCESS);
193 used = isc_buffer_usedlength(b);
194 assert_int_equal(used, 3);
195
196 result = isc_buffer_printf(b, "bar");
197 assert_int_equal(result, ISC_R_SUCCESS);
198 used = isc_buffer_usedlength(b);
199 assert_int_equal(used, 3 + 3);
200
201 /*
202 * Also check the terminating NULL byte is there, even though it is not
203 * part of the buffer's used region.
204 */
205 assert_memory_equal(isc_buffer_current(b), "foobar", 7);
206
207 /*
208 * Skip over data from previous check to prevent failures in previous
209 * check from affecting this one.
210 */
211 prev_used = used;
212 isc_buffer_forward(b, prev_used);
213
214 /*
215 * Some standard usage checks.
216 */
217 isc_buffer_printf(b, "%d", 42);
218 used = isc_buffer_usedlength(b);
219 assert_int_equal(used - prev_used, 2);
220
221 isc_buffer_printf(b, "baz%1X", 42);
222 used = isc_buffer_usedlength(b);
223 assert_int_equal(used - prev_used, 2 + 5);
224
225 isc_buffer_printf(b, "%6.1f", 42.42f);
226 used = isc_buffer_usedlength(b);
227 assert_int_equal(used - prev_used, 2 + 5 + 6);
228
229 /*
230 * Also check the terminating NULL byte is there, even though it is not
231 * part of the buffer's used region.
232 */
233 assert_memory_equal(isc_buffer_current(b), "42baz2A 42.4", 14);
234
235 /*
236 * Check an empty format string is properly handled.
237 *
238 * Note: we don't use a string literal for the format string to
239 * avoid triggering [-Werror=format-zero-length].
240 * Note: we have a dummy third argument as some compilers complain
241 * without it.
242 */
243 prev_used = used;
244 empty_fmt = "";
245 result = isc_buffer_printf(b, empty_fmt, "");
246 assert_int_equal(result, ISC_R_SUCCESS);
247 used = isc_buffer_usedlength(b);
248 assert_int_equal(prev_used, used);
249
250 isc_buffer_free(&b);
251
252 /*
253 * Check overflow on a static buffer.
254 */
255 isc_buffer_init(&sb, buf, sizeof(buf));
256 result = isc_buffer_printf(&sb, "123456");
257 assert_int_equal(result, ISC_R_SUCCESS);
258 used = isc_buffer_usedlength(&sb);
259 assert_int_equal(used, 6);
260
261 result = isc_buffer_printf(&sb, "789");
262 assert_int_equal(result, ISC_R_NOSPACE);
263 used = isc_buffer_usedlength(&sb);
264 assert_int_equal(used, 6);
265
266 result = isc_buffer_printf(&sb, "78");
267 assert_int_equal(result, ISC_R_NOSPACE);
268 used = isc_buffer_usedlength(&sb);
269 assert_int_equal(used, 6);
270
271 result = isc_buffer_printf(&sb, "7");
272 assert_int_equal(result, ISC_R_SUCCESS);
273 used = isc_buffer_usedlength(&sb);
274 assert_int_equal(used, 7);
275 }
276
277 ISC_TEST_LIST_START
278
279 ISC_TEST_ENTRY(isc_buffer_reserve)
280 ISC_TEST_ENTRY(isc_buffer_dynamic)
281 ISC_TEST_ENTRY(isc_buffer_copyregion)
282 ISC_TEST_ENTRY(isc_buffer_printf)
283
284 ISC_TEST_LIST_END
285
286 ISC_TEST_MAIN
287