1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*! \file */
15 
16 #include <inttypes.h>
17 #include <stdarg.h>
18 #include <stdbool.h>
19 
20 #include <isc/buffer.h>
21 #include <isc/mem.h>
22 #include <isc/print.h>
23 #include <isc/region.h>
24 #include <isc/string.h>
25 #include <isc/util.h>
26 
27 void
isc__buffer_init(isc_buffer_t * b,void * base,unsigned int length)28 isc__buffer_init(isc_buffer_t *b, void *base, unsigned int length) {
29 	/*
30 	 * Make 'b' refer to the 'length'-byte region starting at 'base'.
31 	 * XXXDCL see the comment in buffer.h about base being const.
32 	 */
33 
34 	REQUIRE(b != NULL);
35 
36 	ISC__BUFFER_INIT(b, base, length);
37 }
38 
39 void
isc__buffer_initnull(isc_buffer_t * b)40 isc__buffer_initnull(isc_buffer_t *b) {
41 	/*
42 	 * Initialize a new buffer which has no backing store.  This can
43 	 * later be grown as needed and swapped in place.
44 	 */
45 
46 	ISC__BUFFER_INIT(b, NULL, 0);
47 }
48 
49 void
isc_buffer_reinit(isc_buffer_t * b,void * base,unsigned int length)50 isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length) {
51 	/*
52 	 * Re-initialize the buffer enough to reconfigure the base of the
53 	 * buffer.  We will swap in the new buffer, after copying any
54 	 * data we contain into the new buffer and adjusting all of our
55 	 * internal pointers.
56 	 *
57 	 * The buffer must not be smaller than the length of the original
58 	 * buffer.
59 	 */
60 	REQUIRE(b->length <= length);
61 	REQUIRE(base != NULL);
62 	REQUIRE(!b->autore);
63 
64 	if (b->length > 0U) {
65 		(void)memmove(base, b->base, b->length);
66 	}
67 
68 	b->base = base;
69 	b->length = length;
70 }
71 
72 void
isc__buffer_invalidate(isc_buffer_t * b)73 isc__buffer_invalidate(isc_buffer_t *b) {
74 	/*
75 	 * Make 'b' an invalid buffer.
76 	 */
77 
78 	REQUIRE(ISC_BUFFER_VALID(b));
79 	REQUIRE(!ISC_LINK_LINKED(b, link));
80 	REQUIRE(b->mctx == NULL);
81 
82 	ISC__BUFFER_INVALIDATE(b);
83 }
84 
85 void
isc_buffer_setautorealloc(isc_buffer_t * b,bool enable)86 isc_buffer_setautorealloc(isc_buffer_t *b, bool enable) {
87 	REQUIRE(ISC_BUFFER_VALID(b));
88 	REQUIRE(b->mctx != NULL);
89 	b->autore = enable;
90 }
91 
92 void
isc__buffer_region(isc_buffer_t * b,isc_region_t * r)93 isc__buffer_region(isc_buffer_t *b, isc_region_t *r) {
94 	/*
95 	 * Make 'r' refer to the region of 'b'.
96 	 */
97 
98 	REQUIRE(ISC_BUFFER_VALID(b));
99 	REQUIRE(r != NULL);
100 
101 	ISC__BUFFER_REGION(b, r);
102 }
103 
104 void
isc__buffer_usedregion(const isc_buffer_t * b,isc_region_t * r)105 isc__buffer_usedregion(const isc_buffer_t *b, isc_region_t *r) {
106 	/*
107 	 * Make 'r' refer to the used region of 'b'.
108 	 */
109 
110 	REQUIRE(ISC_BUFFER_VALID(b));
111 	REQUIRE(r != NULL);
112 
113 	ISC__BUFFER_USEDREGION(b, r);
114 }
115 
116 void
isc__buffer_availableregion(isc_buffer_t * b,isc_region_t * r)117 isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) {
118 	/*
119 	 * Make 'r' refer to the available region of 'b'.
120 	 */
121 
122 	REQUIRE(ISC_BUFFER_VALID(b));
123 	REQUIRE(r != NULL);
124 
125 	ISC__BUFFER_AVAILABLEREGION(b, r);
126 }
127 
128 void
isc__buffer_add(isc_buffer_t * b,unsigned int n)129 isc__buffer_add(isc_buffer_t *b, unsigned int n) {
130 	/*
131 	 * Increase the 'used' region of 'b' by 'n' bytes.
132 	 */
133 
134 	REQUIRE(ISC_BUFFER_VALID(b));
135 	REQUIRE(b->used + n <= b->length);
136 
137 	ISC__BUFFER_ADD(b, n);
138 }
139 
140 void
isc__buffer_subtract(isc_buffer_t * b,unsigned int n)141 isc__buffer_subtract(isc_buffer_t *b, unsigned int n) {
142 	/*
143 	 * Decrease the 'used' region of 'b' by 'n' bytes.
144 	 */
145 
146 	REQUIRE(ISC_BUFFER_VALID(b));
147 	REQUIRE(b->used >= n);
148 
149 	ISC__BUFFER_SUBTRACT(b, n);
150 }
151 
152 void
isc__buffer_clear(isc_buffer_t * b)153 isc__buffer_clear(isc_buffer_t *b) {
154 	/*
155 	 * Make the used region empty.
156 	 */
157 
158 	REQUIRE(ISC_BUFFER_VALID(b));
159 
160 	ISC__BUFFER_CLEAR(b);
161 }
162 
163 void
isc__buffer_consumedregion(isc_buffer_t * b,isc_region_t * r)164 isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) {
165 	/*
166 	 * Make 'r' refer to the consumed region of 'b'.
167 	 */
168 
169 	REQUIRE(ISC_BUFFER_VALID(b));
170 	REQUIRE(r != NULL);
171 
172 	ISC__BUFFER_CONSUMEDREGION(b, r);
173 }
174 
175 void
isc__buffer_remainingregion(isc_buffer_t * b,isc_region_t * r)176 isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) {
177 	/*
178 	 * Make 'r' refer to the remaining region of 'b'.
179 	 */
180 
181 	REQUIRE(ISC_BUFFER_VALID(b));
182 	REQUIRE(r != NULL);
183 
184 	ISC__BUFFER_REMAININGREGION(b, r);
185 }
186 
187 void
isc__buffer_activeregion(isc_buffer_t * b,isc_region_t * r)188 isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) {
189 	/*
190 	 * Make 'r' refer to the active region of 'b'.
191 	 */
192 
193 	REQUIRE(ISC_BUFFER_VALID(b));
194 	REQUIRE(r != NULL);
195 
196 	ISC__BUFFER_ACTIVEREGION(b, r);
197 }
198 
199 void
isc__buffer_setactive(isc_buffer_t * b,unsigned int n)200 isc__buffer_setactive(isc_buffer_t *b, unsigned int n) {
201 	/*
202 	 * Sets the end of the active region 'n' bytes after current.
203 	 */
204 
205 	REQUIRE(ISC_BUFFER_VALID(b));
206 	REQUIRE(b->current + n <= b->used);
207 
208 	ISC__BUFFER_SETACTIVE(b, n);
209 }
210 
211 void
isc__buffer_first(isc_buffer_t * b)212 isc__buffer_first(isc_buffer_t *b) {
213 	/*
214 	 * Make the consumed region empty.
215 	 */
216 
217 	REQUIRE(ISC_BUFFER_VALID(b));
218 
219 	ISC__BUFFER_FIRST(b);
220 }
221 
222 void
isc__buffer_forward(isc_buffer_t * b,unsigned int n)223 isc__buffer_forward(isc_buffer_t *b, unsigned int n) {
224 	/*
225 	 * Increase the 'consumed' region of 'b' by 'n' bytes.
226 	 */
227 
228 	REQUIRE(ISC_BUFFER_VALID(b));
229 	REQUIRE(b->current + n <= b->used);
230 
231 	ISC__BUFFER_FORWARD(b, n);
232 }
233 
234 void
isc__buffer_back(isc_buffer_t * b,unsigned int n)235 isc__buffer_back(isc_buffer_t *b, unsigned int n) {
236 	/*
237 	 * Decrease the 'consumed' region of 'b' by 'n' bytes.
238 	 */
239 
240 	REQUIRE(ISC_BUFFER_VALID(b));
241 	REQUIRE(n <= b->current);
242 
243 	ISC__BUFFER_BACK(b, n);
244 }
245 
246 void
isc_buffer_compact(isc_buffer_t * b)247 isc_buffer_compact(isc_buffer_t *b) {
248 	unsigned int length;
249 	void *src;
250 
251 	/*
252 	 * Compact the used region by moving the remaining region so it occurs
253 	 * at the start of the buffer.  The used region is shrunk by the size
254 	 * of the consumed region, and the consumed region is then made empty.
255 	 */
256 
257 	REQUIRE(ISC_BUFFER_VALID(b));
258 
259 	src = isc_buffer_current(b);
260 	length = isc_buffer_remaininglength(b);
261 	if (length > 0U) {
262 		(void)memmove(b->base, src, (size_t)length);
263 	}
264 
265 	if (b->active > b->current) {
266 		b->active -= b->current;
267 	} else {
268 		b->active = 0;
269 	}
270 	b->current = 0;
271 	b->used = length;
272 }
273 
274 uint8_t
isc_buffer_getuint8(isc_buffer_t * b)275 isc_buffer_getuint8(isc_buffer_t *b) {
276 	unsigned char *cp;
277 	uint8_t result;
278 
279 	/*
280 	 * Read an unsigned 8-bit integer from 'b' and return it.
281 	 */
282 
283 	REQUIRE(ISC_BUFFER_VALID(b));
284 	REQUIRE(b->used - b->current >= 1);
285 
286 	cp = isc_buffer_current(b);
287 	b->current += 1;
288 	result = ((uint8_t)(cp[0]));
289 
290 	return (result);
291 }
292 
293 void
isc__buffer_putuint8(isc_buffer_t * b,uint8_t val)294 isc__buffer_putuint8(isc_buffer_t *b, uint8_t val) {
295 	isc_result_t result;
296 	REQUIRE(ISC_BUFFER_VALID(b));
297 	if (ISC_UNLIKELY(b->autore)) {
298 		result = isc_buffer_reserve(&b, 1);
299 		REQUIRE(result == ISC_R_SUCCESS);
300 	}
301 	REQUIRE(isc_buffer_availablelength(b) >= 1);
302 
303 	ISC__BUFFER_PUTUINT8(b, val);
304 }
305 
306 uint16_t
isc_buffer_getuint16(isc_buffer_t * b)307 isc_buffer_getuint16(isc_buffer_t *b) {
308 	unsigned char *cp;
309 	uint16_t result;
310 
311 	/*
312 	 * Read an unsigned 16-bit integer in network byte order from 'b',
313 	 * convert it to host byte order, and return it.
314 	 */
315 
316 	REQUIRE(ISC_BUFFER_VALID(b));
317 	REQUIRE(b->used - b->current >= 2);
318 
319 	cp = isc_buffer_current(b);
320 	b->current += 2;
321 	result = ((unsigned int)(cp[0])) << 8;
322 	result |= ((unsigned int)(cp[1]));
323 
324 	return (result);
325 }
326 
327 void
isc__buffer_putuint16(isc_buffer_t * b,uint16_t val)328 isc__buffer_putuint16(isc_buffer_t *b, uint16_t val) {
329 	isc_result_t result;
330 	REQUIRE(ISC_BUFFER_VALID(b));
331 	if (ISC_UNLIKELY(b->autore)) {
332 		result = isc_buffer_reserve(&b, 2);
333 		REQUIRE(result == ISC_R_SUCCESS);
334 	}
335 	REQUIRE(isc_buffer_availablelength(b) >= 2);
336 
337 	ISC__BUFFER_PUTUINT16(b, val);
338 }
339 
340 void
isc__buffer_putuint24(isc_buffer_t * b,uint32_t val)341 isc__buffer_putuint24(isc_buffer_t *b, uint32_t val) {
342 	isc_result_t result;
343 	REQUIRE(ISC_BUFFER_VALID(b));
344 	if (ISC_UNLIKELY(b->autore)) {
345 		result = isc_buffer_reserve(&b, 3);
346 		REQUIRE(result == ISC_R_SUCCESS);
347 	}
348 	REQUIRE(isc_buffer_availablelength(b) >= 3);
349 
350 	ISC__BUFFER_PUTUINT24(b, val);
351 }
352 
353 uint32_t
isc_buffer_getuint32(isc_buffer_t * b)354 isc_buffer_getuint32(isc_buffer_t *b) {
355 	unsigned char *cp;
356 	uint32_t result;
357 
358 	/*
359 	 * Read an unsigned 32-bit integer in network byte order from 'b',
360 	 * convert it to host byte order, and return it.
361 	 */
362 
363 	REQUIRE(ISC_BUFFER_VALID(b));
364 	REQUIRE(b->used - b->current >= 4);
365 
366 	cp = isc_buffer_current(b);
367 	b->current += 4;
368 	result = ((unsigned int)(cp[0])) << 24;
369 	result |= ((unsigned int)(cp[1])) << 16;
370 	result |= ((unsigned int)(cp[2])) << 8;
371 	result |= ((unsigned int)(cp[3]));
372 
373 	return (result);
374 }
375 
376 void
isc__buffer_putuint32(isc_buffer_t * b,uint32_t val)377 isc__buffer_putuint32(isc_buffer_t *b, uint32_t val) {
378 	isc_result_t result;
379 	REQUIRE(ISC_BUFFER_VALID(b));
380 	if (ISC_UNLIKELY(b->autore)) {
381 		result = isc_buffer_reserve(&b, 4);
382 		REQUIRE(result == ISC_R_SUCCESS);
383 	}
384 	REQUIRE(isc_buffer_availablelength(b) >= 4);
385 
386 	ISC__BUFFER_PUTUINT32(b, val);
387 }
388 
389 uint64_t
isc_buffer_getuint48(isc_buffer_t * b)390 isc_buffer_getuint48(isc_buffer_t *b) {
391 	unsigned char *cp;
392 	uint64_t result;
393 
394 	/*
395 	 * Read an unsigned 48-bit integer in network byte order from 'b',
396 	 * convert it to host byte order, and return it.
397 	 */
398 
399 	REQUIRE(ISC_BUFFER_VALID(b));
400 	REQUIRE(b->used - b->current >= 6);
401 
402 	cp = isc_buffer_current(b);
403 	b->current += 6;
404 	result = ((int64_t)(cp[0])) << 40;
405 	result |= ((int64_t)(cp[1])) << 32;
406 	result |= ((int64_t)(cp[2])) << 24;
407 	result |= ((int64_t)(cp[3])) << 16;
408 	result |= ((int64_t)(cp[4])) << 8;
409 	result |= ((int64_t)(cp[5]));
410 
411 	return (result);
412 }
413 
414 void
isc__buffer_putuint48(isc_buffer_t * b,uint64_t val)415 isc__buffer_putuint48(isc_buffer_t *b, uint64_t val) {
416 	isc_result_t result;
417 	uint16_t valhi;
418 	uint32_t vallo;
419 
420 	REQUIRE(ISC_BUFFER_VALID(b));
421 	if (ISC_UNLIKELY(b->autore)) {
422 		result = isc_buffer_reserve(&b, 6);
423 		REQUIRE(result == ISC_R_SUCCESS);
424 	}
425 	REQUIRE(isc_buffer_availablelength(b) >= 6);
426 
427 	valhi = (uint16_t)(val >> 32);
428 	vallo = (uint32_t)(val & 0xFFFFFFFF);
429 	ISC__BUFFER_PUTUINT16(b, valhi);
430 	ISC__BUFFER_PUTUINT32(b, vallo);
431 }
432 
433 void
isc__buffer_putmem(isc_buffer_t * b,const unsigned char * base,unsigned int length)434 isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
435 		   unsigned int length) {
436 	isc_result_t result;
437 	REQUIRE(ISC_BUFFER_VALID(b));
438 	if (ISC_UNLIKELY(b->autore)) {
439 		result = isc_buffer_reserve(&b, length);
440 		REQUIRE(result == ISC_R_SUCCESS);
441 	}
442 	REQUIRE(isc_buffer_availablelength(b) >= length);
443 
444 	ISC__BUFFER_PUTMEM(b, base, length);
445 }
446 
447 void
isc__buffer_putstr(isc_buffer_t * b,const char * source)448 isc__buffer_putstr(isc_buffer_t *b, const char *source) {
449 	unsigned int l;
450 	unsigned char *cp;
451 	isc_result_t result;
452 
453 	REQUIRE(ISC_BUFFER_VALID(b));
454 	REQUIRE(source != NULL);
455 
456 	/*
457 	 * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once.
458 	 */
459 	l = strlen(source);
460 	if (ISC_UNLIKELY(b->autore)) {
461 		result = isc_buffer_reserve(&b, l);
462 		REQUIRE(result == ISC_R_SUCCESS);
463 	}
464 	REQUIRE(isc_buffer_availablelength(b) >= l);
465 
466 	cp = isc_buffer_used(b);
467 	memmove(cp, source, l);
468 	b->used += l;
469 }
470 
471 void
isc_buffer_putdecint(isc_buffer_t * b,int64_t v)472 isc_buffer_putdecint(isc_buffer_t *b, int64_t v) {
473 	unsigned int l = 0;
474 	unsigned char *cp;
475 	char buf[21];
476 	isc_result_t result;
477 
478 	REQUIRE(ISC_BUFFER_VALID(b));
479 
480 	/* xxxwpk do it more low-level way ? */
481 	l = snprintf(buf, 21, "%" PRId64, v);
482 	RUNTIME_CHECK(l <= 21);
483 	if (ISC_UNLIKELY(b->autore)) {
484 		result = isc_buffer_reserve(&b, l);
485 		REQUIRE(result == ISC_R_SUCCESS);
486 	}
487 	REQUIRE(isc_buffer_availablelength(b) >= l);
488 
489 	cp = isc_buffer_used(b);
490 	memmove(cp, buf, l);
491 	b->used += l;
492 }
493 
494 isc_result_t
isc_buffer_dup(isc_mem_t * mctx,isc_buffer_t ** dstp,const isc_buffer_t * src)495 isc_buffer_dup(isc_mem_t *mctx, isc_buffer_t **dstp, const isc_buffer_t *src) {
496 	isc_buffer_t *dst = NULL;
497 	isc_region_t region;
498 	isc_result_t result;
499 
500 	REQUIRE(dstp != NULL && *dstp == NULL);
501 	REQUIRE(ISC_BUFFER_VALID(src));
502 
503 	isc_buffer_usedregion(src, &region);
504 
505 	isc_buffer_allocate(mctx, &dst, region.length);
506 
507 	result = isc_buffer_copyregion(dst, &region);
508 	RUNTIME_CHECK(result == ISC_R_SUCCESS); /* NOSPACE is impossible */
509 	*dstp = dst;
510 	return (ISC_R_SUCCESS);
511 }
512 
513 isc_result_t
isc_buffer_copyregion(isc_buffer_t * b,const isc_region_t * r)514 isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) {
515 	isc_result_t result;
516 
517 	REQUIRE(ISC_BUFFER_VALID(b));
518 	REQUIRE(r != NULL);
519 
520 	if (ISC_UNLIKELY(b->autore)) {
521 		result = isc_buffer_reserve(&b, r->length);
522 		if (result != ISC_R_SUCCESS) {
523 			return (result);
524 		}
525 	}
526 
527 	if (r->length > isc_buffer_availablelength(b)) {
528 		return (ISC_R_NOSPACE);
529 	}
530 
531 	if (r->length > 0U) {
532 		memmove(isc_buffer_used(b), r->base, r->length);
533 		b->used += r->length;
534 	}
535 
536 	return (ISC_R_SUCCESS);
537 }
538 
539 void
isc_buffer_allocate(isc_mem_t * mctx,isc_buffer_t ** dynbuffer,unsigned int length)540 isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
541 		    unsigned int length) {
542 	REQUIRE(dynbuffer != NULL && *dynbuffer == NULL);
543 
544 	isc_buffer_t *dbuf = isc_mem_get(mctx, sizeof(isc_buffer_t));
545 	unsigned char *bdata = isc_mem_get(mctx, length);
546 
547 	isc_buffer_init(dbuf, bdata, length);
548 
549 	ENSURE(ISC_BUFFER_VALID(dbuf));
550 
551 	dbuf->mctx = mctx;
552 
553 	*dynbuffer = dbuf;
554 }
555 
556 isc_result_t
isc_buffer_reserve(isc_buffer_t ** dynbuffer,unsigned int size)557 isc_buffer_reserve(isc_buffer_t **dynbuffer, unsigned int size) {
558 	unsigned char *bdata;
559 	uint64_t len;
560 
561 	REQUIRE(dynbuffer != NULL);
562 	REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
563 
564 	len = (*dynbuffer)->length;
565 	if ((len - (*dynbuffer)->used) >= size) {
566 		return (ISC_R_SUCCESS);
567 	}
568 
569 	if ((*dynbuffer)->mctx == NULL) {
570 		return (ISC_R_NOSPACE);
571 	}
572 
573 	/* Round to nearest buffer size increment */
574 	len = size + (*dynbuffer)->used;
575 	len = (len + ISC_BUFFER_INCR - 1 - ((len - 1) % ISC_BUFFER_INCR));
576 
577 	/* Cap at UINT_MAX */
578 	if (len > UINT_MAX) {
579 		len = UINT_MAX;
580 	}
581 
582 	if ((len - (*dynbuffer)->used) < size) {
583 		return (ISC_R_NOMEMORY);
584 	}
585 
586 	/*
587 	 * XXXMUKS: This is far more expensive than plain realloc() as
588 	 * it doesn't remap pages, but does ordinary copy. So is
589 	 * isc_mem_reallocate(), which has additional issues.
590 	 */
591 	bdata = isc_mem_get((*dynbuffer)->mctx, (unsigned int)len);
592 
593 	memmove(bdata, (*dynbuffer)->base, (*dynbuffer)->length);
594 	isc_mem_put((*dynbuffer)->mctx, (*dynbuffer)->base,
595 		    (*dynbuffer)->length);
596 
597 	(*dynbuffer)->base = bdata;
598 	(*dynbuffer)->length = (unsigned int)len;
599 
600 	return (ISC_R_SUCCESS);
601 }
602 
603 void
isc_buffer_free(isc_buffer_t ** dynbuffer)604 isc_buffer_free(isc_buffer_t **dynbuffer) {
605 	isc_buffer_t *dbuf;
606 	isc_mem_t *mctx;
607 
608 	REQUIRE(dynbuffer != NULL);
609 	REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
610 	REQUIRE((*dynbuffer)->mctx != NULL);
611 
612 	dbuf = *dynbuffer;
613 	*dynbuffer = NULL; /* destroy external reference */
614 	mctx = dbuf->mctx;
615 	dbuf->mctx = NULL;
616 
617 	isc_mem_put(mctx, dbuf->base, dbuf->length);
618 	isc_buffer_invalidate(dbuf);
619 	isc_mem_put(mctx, dbuf, sizeof(isc_buffer_t));
620 }
621 
622 isc_result_t
isc_buffer_printf(isc_buffer_t * b,const char * format,...)623 isc_buffer_printf(isc_buffer_t *b, const char *format, ...) {
624 	va_list ap;
625 	int n;
626 	isc_result_t result;
627 
628 	REQUIRE(ISC_BUFFER_VALID(b));
629 
630 	va_start(ap, format);
631 	n = vsnprintf(NULL, 0, format, ap);
632 	va_end(ap);
633 
634 	if (n < 0) {
635 		return (ISC_R_FAILURE);
636 	}
637 
638 	if (ISC_UNLIKELY(b->autore)) {
639 		result = isc_buffer_reserve(&b, n + 1);
640 		if (result != ISC_R_SUCCESS) {
641 			return (result);
642 		}
643 	}
644 
645 	if (isc_buffer_availablelength(b) < (unsigned int)n + 1) {
646 		return (ISC_R_NOSPACE);
647 	}
648 
649 	va_start(ap, format);
650 	n = vsnprintf(isc_buffer_used(b), n + 1, format, ap);
651 	va_end(ap);
652 
653 	if (n < 0) {
654 		return (ISC_R_FAILURE);
655 	}
656 
657 	b->used += n;
658 
659 	return (ISC_R_SUCCESS);
660 }
661