xref: /netbsd-src/external/mpl/bind/dist/tests/isc/buffer_test.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
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