1 /* $NetBSD: buffer_test.c,v 1.2 2024/02/21 22:52:50 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/print.h> 33 #include <isc/region.h> 34 #include <isc/result.h> 35 #include <isc/types.h> 36 #include <isc/util.h> 37 38 #include <tests/isc.h> 39 40 /* reserve space in dynamic buffers */ 41 ISC_RUN_TEST_IMPL(isc_buffer_reserve) { 42 isc_result_t result; 43 isc_buffer_t *b; 44 45 UNUSED(state); 46 47 b = NULL; 48 isc_buffer_allocate(mctx, &b, 1024); 49 assert_int_equal(b->length, 1024); 50 51 /* 52 * 1024 bytes should already be available, so this call does 53 * nothing. 54 */ 55 result = isc_buffer_reserve(&b, 1024); 56 assert_int_equal(result, ISC_R_SUCCESS); 57 assert_true(ISC_BUFFER_VALID(b)); 58 assert_non_null(b); 59 assert_int_equal(b->length, 1024); 60 61 /* 62 * This call should grow it to 2048 bytes as only 1024 bytes are 63 * available in the buffer. 64 */ 65 result = isc_buffer_reserve(&b, 1025); 66 assert_int_equal(result, ISC_R_SUCCESS); 67 assert_true(ISC_BUFFER_VALID(b)); 68 assert_non_null(b); 69 assert_int_equal(b->length, 2048); 70 71 /* 72 * 2048 bytes should already be available, so this call does 73 * nothing. 74 */ 75 result = isc_buffer_reserve(&b, 2000); 76 assert_int_equal(result, ISC_R_SUCCESS); 77 assert_true(ISC_BUFFER_VALID(b)); 78 assert_non_null(b); 79 assert_int_equal(b->length, 2048); 80 81 /* 82 * This call should grow it to 4096 bytes as only 2048 bytes are 83 * available in the buffer. 84 */ 85 result = isc_buffer_reserve(&b, 3000); 86 assert_int_equal(result, ISC_R_SUCCESS); 87 assert_true(ISC_BUFFER_VALID(b)); 88 assert_non_null(b); 89 assert_int_equal(b->length, 4096); 90 91 /* Consume some of the buffer so we can run the next test. */ 92 isc_buffer_add(b, 4096); 93 94 /* 95 * This call should fail and leave buffer untouched. 96 */ 97 result = isc_buffer_reserve(&b, UINT_MAX); 98 assert_int_equal(result, ISC_R_NOMEMORY); 99 assert_true(ISC_BUFFER_VALID(b)); 100 assert_non_null(b); 101 assert_int_equal(b->length, 4096); 102 103 isc_buffer_free(&b); 104 } 105 106 /* dynamic buffer automatic reallocation */ 107 ISC_RUN_TEST_IMPL(isc_buffer_dynamic) { 108 isc_buffer_t *b; 109 size_t last_length = 10; 110 int i; 111 112 UNUSED(state); 113 114 b = NULL; 115 isc_buffer_allocate(mctx, &b, last_length); 116 assert_non_null(b); 117 assert_int_equal(b->length, last_length); 118 119 isc_buffer_setautorealloc(b, true); 120 121 isc_buffer_putuint8(b, 1); 122 123 for (i = 0; i < 1000; i++) { 124 isc_buffer_putstr(b, "thisisa24charslongstring"); 125 } 126 assert_true(b->length - last_length >= 1000 * 24); 127 last_length += 1000 * 24; 128 129 for (i = 0; i < 10000; i++) { 130 isc_buffer_putuint8(b, 1); 131 } 132 133 assert_true(b->length - last_length >= 10000 * 1); 134 last_length += 10000 * 1; 135 136 for (i = 0; i < 10000; i++) { 137 isc_buffer_putuint16(b, 1); 138 } 139 140 assert_true(b->length - last_length >= 10000 * 2); 141 142 last_length += 10000 * 2; 143 for (i = 0; i < 10000; i++) { 144 isc_buffer_putuint24(b, 1); 145 } 146 assert_true(b->length - last_length >= 10000 * 3); 147 148 last_length += 10000 * 3; 149 150 for (i = 0; i < 10000; i++) { 151 isc_buffer_putuint32(b, 1); 152 } 153 assert_true(b->length - last_length >= 10000 * 4); 154 155 isc_buffer_free(&b); 156 } 157 158 /* copy a region into a buffer */ 159 ISC_RUN_TEST_IMPL(isc_buffer_copyregion) { 160 unsigned char data[] = { 0x11, 0x22, 0x33, 0x44 }; 161 isc_buffer_t *b = NULL; 162 isc_result_t result; 163 164 isc_region_t r = { 165 .base = data, 166 .length = sizeof(data), 167 }; 168 169 UNUSED(state); 170 171 isc_buffer_allocate(mctx, &b, sizeof(data)); 172 173 /* 174 * Fill originally allocated buffer space. 175 */ 176 result = isc_buffer_copyregion(b, &r); 177 assert_int_equal(result, ISC_R_SUCCESS); 178 179 /* 180 * Appending more data to the buffer should fail. 181 */ 182 result = isc_buffer_copyregion(b, &r); 183 assert_int_equal(result, ISC_R_NOSPACE); 184 185 /* 186 * Enable auto reallocation and retry. Appending should now succeed. 187 */ 188 isc_buffer_setautorealloc(b, true); 189 result = isc_buffer_copyregion(b, &r); 190 assert_int_equal(result, ISC_R_SUCCESS); 191 192 isc_buffer_free(&b); 193 } 194 195 /* sprintf() into a buffer */ 196 ISC_RUN_TEST_IMPL(isc_buffer_printf) { 197 unsigned int used, prev_used; 198 const char *empty_fmt; 199 isc_result_t result; 200 isc_buffer_t *b, sb; 201 char buf[8]; 202 203 UNUSED(state); 204 205 /* 206 * Prepare a buffer with auto-reallocation enabled. 207 */ 208 b = NULL; 209 isc_buffer_allocate(mctx, &b, 0); 210 isc_buffer_setautorealloc(b, true); 211 212 /* 213 * Sanity check. 214 */ 215 result = isc_buffer_printf(b, "foo"); 216 assert_int_equal(result, ISC_R_SUCCESS); 217 used = isc_buffer_usedlength(b); 218 assert_int_equal(used, 3); 219 220 result = isc_buffer_printf(b, "bar"); 221 assert_int_equal(result, ISC_R_SUCCESS); 222 used = isc_buffer_usedlength(b); 223 assert_int_equal(used, 3 + 3); 224 225 /* 226 * Also check the terminating NULL byte is there, even though it is not 227 * part of the buffer's used region. 228 */ 229 assert_memory_equal(isc_buffer_current(b), "foobar", 7); 230 231 /* 232 * Skip over data from previous check to prevent failures in previous 233 * check from affecting this one. 234 */ 235 prev_used = used; 236 isc_buffer_forward(b, prev_used); 237 238 /* 239 * Some standard usage checks. 240 */ 241 isc_buffer_printf(b, "%d", 42); 242 used = isc_buffer_usedlength(b); 243 assert_int_equal(used - prev_used, 2); 244 245 isc_buffer_printf(b, "baz%1X", 42); 246 used = isc_buffer_usedlength(b); 247 assert_int_equal(used - prev_used, 2 + 5); 248 249 isc_buffer_printf(b, "%6.1f", 42.42f); 250 used = isc_buffer_usedlength(b); 251 assert_int_equal(used - prev_used, 2 + 5 + 6); 252 253 /* 254 * Also check the terminating NULL byte is there, even though it is not 255 * part of the buffer's used region. 256 */ 257 assert_memory_equal(isc_buffer_current(b), "42baz2A 42.4", 14); 258 259 /* 260 * Check an empty format string is properly handled. 261 * 262 * Note: we don't use a string literal for the format string to 263 * avoid triggering [-Werror=format-zero-length]. 264 * Note: we have a dummy third argument as some compilers complain 265 * without it. 266 */ 267 prev_used = used; 268 empty_fmt = ""; 269 result = isc_buffer_printf(b, empty_fmt, ""); 270 assert_int_equal(result, ISC_R_SUCCESS); 271 used = isc_buffer_usedlength(b); 272 assert_int_equal(prev_used, used); 273 274 isc_buffer_free(&b); 275 276 /* 277 * Check overflow on a static buffer. 278 */ 279 isc_buffer_init(&sb, buf, sizeof(buf)); 280 result = isc_buffer_printf(&sb, "123456"); 281 assert_int_equal(result, ISC_R_SUCCESS); 282 used = isc_buffer_usedlength(&sb); 283 assert_int_equal(used, 6); 284 285 result = isc_buffer_printf(&sb, "789"); 286 assert_int_equal(result, ISC_R_NOSPACE); 287 used = isc_buffer_usedlength(&sb); 288 assert_int_equal(used, 6); 289 290 result = isc_buffer_printf(&sb, "78"); 291 assert_int_equal(result, ISC_R_NOSPACE); 292 used = isc_buffer_usedlength(&sb); 293 assert_int_equal(used, 6); 294 295 result = isc_buffer_printf(&sb, "7"); 296 assert_int_equal(result, ISC_R_SUCCESS); 297 used = isc_buffer_usedlength(&sb); 298 assert_int_equal(used, 7); 299 } 300 301 ISC_TEST_LIST_START 302 303 ISC_TEST_ENTRY(isc_buffer_reserve) 304 ISC_TEST_ENTRY(isc_buffer_dynamic) 305 ISC_TEST_ENTRY(isc_buffer_copyregion) 306 ISC_TEST_ENTRY(isc_buffer_printf) 307 308 ISC_TEST_LIST_END 309 310 ISC_TEST_MAIN 311