xref: /netbsd/external/mpl/bind/dist/lib/isc/mem.c (revision a706c3b7)
1 /*	$NetBSD: mem.c,v 1.14 2023/06/26 22:03:01 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 /*! \file */
17 
18 #include <errno.h>
19 #include <inttypes.h>
20 #include <limits.h>
21 #include <stdbool.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #include <isc/bind9.h>
27 #include <isc/hash.h>
28 #include <isc/lib.h>
29 #include <isc/magic.h>
30 #include <isc/mem.h>
31 #include <isc/mutex.h>
32 #include <isc/once.h>
33 #include <isc/print.h>
34 #include <isc/refcount.h>
35 #include <isc/strerr.h>
36 #include <isc/string.h>
37 #include <isc/util.h>
38 
39 #ifdef HAVE_LIBXML2
40 #include <libxml/xmlwriter.h>
41 #define ISC_XMLCHAR (const xmlChar *)
42 #endif /* HAVE_LIBXML2 */
43 
44 #ifdef HAVE_JSON_C
45 #include <json_object.h>
46 #endif /* HAVE_JSON_C */
47 
48 #include "mem_p.h"
49 
50 #define MCTXLOCK(m)   LOCK(&m->lock)
51 #define MCTXUNLOCK(m) UNLOCK(&m->lock)
52 
53 #ifndef ISC_MEM_DEBUGGING
54 #define ISC_MEM_DEBUGGING 0
55 #endif /* ifndef ISC_MEM_DEBUGGING */
56 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
57 LIBISC_EXTERNAL_DATA unsigned int isc_mem_defaultflags = ISC_MEMFLAG_DEFAULT;
58 
59 /*
60  * Constants.
61  */
62 
63 #define DEF_MAX_SIZE   1100
64 #define DEF_MEM_TARGET 4096
65 #define ALIGNMENT_SIZE \
66 	8U /*%< must be a power of 2, also update lib/dns/rbt.c */
67 #define NUM_BASIC_BLOCKS  64 /*%< must be > 1 */
68 #define TABLE_INCREMENT	  1024
69 #define DEBUG_TABLE_COUNT 512U
70 
71 /*
72  * Types.
73  */
74 typedef struct isc__mem isc__mem_t;
75 typedef struct isc__mempool isc__mempool_t;
76 
77 #if ISC_MEM_TRACKLINES
78 typedef struct debuglink debuglink_t;
79 struct debuglink {
80 	ISC_LINK(debuglink_t) link;
81 	const void *ptr;
82 	size_t size;
83 	const char *file;
84 	unsigned int line;
85 };
86 
87 typedef ISC_LIST(debuglink_t) debuglist_t;
88 
89 #define FLARG_PASS , file, line
90 #define FLARG	   , const char *file, unsigned int line
91 #else /* if ISC_MEM_TRACKLINES */
92 #define FLARG_PASS
93 #define FLARG
94 #endif /* if ISC_MEM_TRACKLINES */
95 
96 typedef struct element element;
97 struct element {
98 	element *next;
99 };
100 
101 typedef struct {
102 	/*!
103 	 * This structure must be ALIGNMENT_SIZE bytes.
104 	 */
105 	union {
106 		size_t size;
107 		isc__mem_t *ctx;
108 		char bytes[ALIGNMENT_SIZE];
109 	} u;
110 } size_info;
111 
112 struct stats {
113 	unsigned long gets;
114 	unsigned long totalgets;
115 	unsigned long blocks;
116 	unsigned long freefrags;
117 };
118 
119 #define MEM_MAGIC	 ISC_MAGIC('M', 'e', 'm', 'C')
120 #define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
121 
122 /* List of all active memory contexts. */
123 
124 static ISC_LIST(isc__mem_t) contexts;
125 
126 static isc_once_t init_once = ISC_ONCE_INIT;
127 static isc_once_t shut_once = ISC_ONCE_INIT;
128 static isc_mutex_t contextslock;
129 
130 /*%
131  * Total size of lost memory due to a bug of external library.
132  * Locked by the global lock.
133  */
134 static uint64_t totallost;
135 
136 /*%
137  * Memory allocation and free function definitions.
138  * isc__memalloc_t must deal with memory allocation failure
139  * and must never return NULL.
140  */
141 typedef void *(*isc__memalloc_t)(size_t);
142 typedef void (*isc__memfree_t)(void *);
143 
144 struct isc__mem {
145 	isc_mem_t common;
146 	unsigned int flags;
147 	isc_mutex_t lock;
148 	isc__memalloc_t memalloc;
149 	isc__memfree_t memfree;
150 	size_t max_size;
151 	bool checkfree;
152 	struct stats *stats;
153 	isc_refcount_t references;
154 	char name[16];
155 	void *tag;
156 	size_t total;
157 	size_t inuse;
158 	size_t maxinuse;
159 	size_t malloced;
160 	size_t maxmalloced;
161 	size_t hi_water;
162 	size_t lo_water;
163 	bool hi_called;
164 	bool is_overmem;
165 	isc_mem_water_t water;
166 	void *water_arg;
167 	ISC_LIST(isc__mempool_t) pools;
168 	unsigned int poolcnt;
169 
170 	/*  ISC_MEMFLAG_INTERNAL */
171 	size_t mem_target;
172 	element **freelists;
173 	element *basic_blocks;
174 	unsigned char **basic_table;
175 	unsigned int basic_table_count;
176 	unsigned int basic_table_size;
177 	unsigned char *lowest;
178 	unsigned char *highest;
179 
180 #if ISC_MEM_TRACKLINES
181 	debuglist_t *debuglist;
182 	size_t debuglistcnt;
183 #endif /* if ISC_MEM_TRACKLINES */
184 
185 	ISC_LINK(isc__mem_t) link;
186 };
187 
188 #define MEMPOOL_MAGIC	 ISC_MAGIC('M', 'E', 'M', 'p')
189 #define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
190 
191 struct isc__mempool {
192 	/* always unlocked */
193 	isc_mempool_t common;	       /*%< common header of mempool's */
194 	isc__mem_t *mctx;	       /*%< our memory context */
195 	ISC_LINK(isc__mempool_t) link; /*%< next pool in this mem context */
196 	element *items;		       /*%< low water item list */
197 	size_t size;		       /*%< size of each item on this pool */
198 	unsigned int maxalloc;	       /*%< max number of items allowed */
199 	unsigned int allocated;	       /*%< # of items currently given out */
200 	unsigned int freecount;	       /*%< # of items on reserved list */
201 	unsigned int freemax;	       /*%< # of items allowed on free list */
202 	unsigned int fillcount;	       /*%< # of items to fetch on each fill */
203 	/*%< Stats only. */
204 	unsigned int gets; /*%< # of requests to this pool */
205 			   /*%< Debugging only. */
206 #if ISC_MEMPOOL_NAMES
207 	char name[16]; /*%< printed name in stats reports */
208 #endif		       /* if ISC_MEMPOOL_NAMES */
209 };
210 
211 /*
212  * Private Inline-able.
213  */
214 
215 #if !ISC_MEM_TRACKLINES
216 #define ADD_TRACE(a, b, c, d, e)
217 #define DELETE_TRACE(a, b, c, d, e)
218 #define ISC_MEMFUNC_SCOPE
219 #else /* if !ISC_MEM_TRACKLINES */
220 #define TRACE_OR_RECORD (ISC_MEM_DEBUGTRACE | ISC_MEM_DEBUGRECORD)
221 #define ADD_TRACE(a, b, c, d, e)                                               \
222 	do {                                                                   \
223 		if (ISC_UNLIKELY((isc_mem_debugging & TRACE_OR_RECORD) != 0 && \
224 				 b != NULL))                                   \
225 			add_trace_entry(a, b, c, d, e);                        \
226 	} while (0)
227 #define DELETE_TRACE(a, b, c, d, e)                                            \
228 	do {                                                                   \
229 		if (ISC_UNLIKELY((isc_mem_debugging & TRACE_OR_RECORD) != 0 && \
230 				 b != NULL))                                   \
231 			delete_trace_entry(a, b, c, d, e);                     \
232 	} while (0)
233 
234 static void
235 print_active(isc__mem_t *ctx, FILE *out);
236 
237 #endif /* ISC_MEM_TRACKLINES */
238 
239 static void *
240 isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
241 static void
242 isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
243 static void
244 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
245 static void *
246 isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
247 static void *
248 isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
249 static char *
250 isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
251 static char *
252 isc___mem_strndup(isc_mem_t *mctx0, const char *s, size_t size FLARG);
253 static void
254 isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
255 
256 static isc_memmethods_t memmethods = {
257 	isc___mem_get,	    isc___mem_put,	  isc___mem_putanddetach,
258 	isc___mem_allocate, isc___mem_reallocate, isc___mem_strdup,
259 	isc___mem_strndup,  isc___mem_free,
260 };
261 
262 #if ISC_MEM_TRACKLINES
263 /*!
264  * mctx must be locked.
265  */
266 static void
add_trace_entry(isc__mem_t * mctx,const void * ptr,size_t size FLARG)267 add_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size FLARG) {
268 	debuglink_t *dl;
269 	uint32_t hash;
270 	uint32_t idx;
271 
272 	if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
273 		fprintf(stderr, "add %p size %zu file %s line %u mctx %p\n",
274 			ptr, size, file, line, mctx);
275 	}
276 
277 	if (mctx->debuglist == NULL) {
278 		return;
279 	}
280 
281 #ifdef __COVERITY__
282 	/*
283 	 * Use simple conversion from pointer to hash to avoid
284 	 * tainting 'ptr' due to byte swap in isc_hash_function.
285 	 */
286 	hash = (uintptr_t)ptr >> 3;
287 #else
288 	hash = isc_hash_function(&ptr, sizeof(ptr), true);
289 #endif
290 	idx = hash % DEBUG_TABLE_COUNT;
291 
292 	dl = malloc(sizeof(debuglink_t));
293 	INSIST(dl != NULL);
294 	mctx->malloced += sizeof(debuglink_t);
295 	if (mctx->malloced > mctx->maxmalloced) {
296 		mctx->maxmalloced = mctx->malloced;
297 	}
298 
299 	ISC_LINK_INIT(dl, link);
300 	dl->ptr = ptr;
301 	dl->size = size;
302 	dl->file = file;
303 	dl->line = line;
304 
305 	ISC_LIST_PREPEND(mctx->debuglist[idx], dl, link);
306 	mctx->debuglistcnt++;
307 }
308 
309 static void
delete_trace_entry(isc__mem_t * mctx,const void * ptr,size_t size,const char * file,unsigned int line)310 delete_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size,
311 		   const char *file, unsigned int line) {
312 	debuglink_t *dl;
313 	uint32_t hash;
314 	uint32_t idx;
315 
316 	if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
317 		fprintf(stderr, "del %p size %zu file %s line %u mctx %p\n",
318 			ptr, size, file, line, mctx);
319 	}
320 
321 	if (mctx->debuglist == NULL) {
322 		return;
323 	}
324 
325 #ifdef __COVERITY__
326 	/*
327 	 * Use simple conversion from pointer to hash to avoid
328 	 * tainting 'ptr' due to byte swap in isc_hash_function.
329 	 */
330 	hash = (uintptr_t)ptr >> 3;
331 #else
332 	hash = isc_hash_function(&ptr, sizeof(ptr), true);
333 #endif
334 	idx = hash % DEBUG_TABLE_COUNT;
335 
336 	dl = ISC_LIST_HEAD(mctx->debuglist[idx]);
337 	while (ISC_LIKELY(dl != NULL)) {
338 		if (ISC_UNLIKELY(dl->ptr == ptr)) {
339 			ISC_LIST_UNLINK(mctx->debuglist[idx], dl, link);
340 			mctx->malloced -= sizeof(*dl);
341 			free(dl);
342 			return;
343 		}
344 		dl = ISC_LIST_NEXT(dl, link);
345 	}
346 
347 	/*
348 	 * If we get here, we didn't find the item on the list.  We're
349 	 * screwed.
350 	 */
351 	UNREACHABLE();
352 }
353 #endif /* ISC_MEM_TRACKLINES */
354 
355 static size_t
rmsize(size_t size)356 rmsize(size_t size) {
357 	/*
358 	 * round down to ALIGNMENT_SIZE
359 	 */
360 	return (size & (~(ALIGNMENT_SIZE - 1)));
361 }
362 
363 static size_t
quantize(size_t size)364 quantize(size_t size) {
365 	/*!
366 	 * Round up the result in order to get a size big
367 	 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
368 	 * byte boundaries.
369 	 */
370 
371 	if (size == 0U) {
372 		return (ALIGNMENT_SIZE);
373 	}
374 	return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
375 }
376 
377 static void
more_basic_blocks(isc__mem_t * ctx)378 more_basic_blocks(isc__mem_t *ctx) {
379 	void *tmp;
380 	unsigned char *curr, *next;
381 	unsigned char *first, *last;
382 	unsigned char **table;
383 	unsigned int table_size;
384 
385 	/* Require: we hold the context lock. */
386 
387 	INSIST(ctx->basic_table_count <= ctx->basic_table_size);
388 	if (ctx->basic_table_count == ctx->basic_table_size) {
389 		table_size = ctx->basic_table_size + TABLE_INCREMENT;
390 		table = (ctx->memalloc)(table_size * sizeof(unsigned char *));
391 		ctx->malloced += table_size * sizeof(unsigned char *);
392 		if (ctx->malloced > ctx->maxmalloced) {
393 			ctx->maxmalloced = ctx->malloced;
394 		}
395 		if (ctx->basic_table_size != 0) {
396 			memmove(table, ctx->basic_table,
397 				ctx->basic_table_size *
398 					sizeof(unsigned char *));
399 			(ctx->memfree)(ctx->basic_table);
400 			ctx->malloced -= ctx->basic_table_size *
401 					 sizeof(unsigned char *);
402 		}
403 		ctx->basic_table = table;
404 		ctx->basic_table_size = table_size;
405 	}
406 
407 	tmp = (ctx->memalloc)(NUM_BASIC_BLOCKS * ctx->mem_target);
408 	ctx->total += NUM_BASIC_BLOCKS * ctx->mem_target;
409 	ctx->basic_table[ctx->basic_table_count] = tmp;
410 	ctx->basic_table_count++;
411 	ctx->malloced += NUM_BASIC_BLOCKS * ctx->mem_target;
412 	if (ctx->malloced > ctx->maxmalloced) {
413 		ctx->maxmalloced = ctx->malloced;
414 	}
415 
416 	curr = tmp;
417 	next = curr + ctx->mem_target;
418 	for (int i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
419 		((element *)curr)->next = (element *)next;
420 		curr = next;
421 		next += ctx->mem_target;
422 	}
423 	/*
424 	 * curr is now pointing at the last block in the
425 	 * array.
426 	 */
427 	((element *)curr)->next = NULL;
428 	first = tmp;
429 	last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
430 	if (first < ctx->lowest || ctx->lowest == NULL) {
431 		ctx->lowest = first;
432 	}
433 	if (last > ctx->highest) {
434 		ctx->highest = last;
435 	}
436 	ctx->basic_blocks = tmp;
437 }
438 
439 static void
more_frags(isc__mem_t * ctx,size_t new_size)440 more_frags(isc__mem_t *ctx, size_t new_size) {
441 	int frags;
442 	size_t total_size;
443 	void *tmp;
444 	unsigned char *curr, *next;
445 
446 	/*!
447 	 * Try to get more fragments by chopping up a basic block.
448 	 */
449 
450 	if (ctx->basic_blocks == NULL) {
451 		more_basic_blocks(ctx);
452 	}
453 	INSIST(ctx->basic_blocks != NULL);
454 
455 	total_size = ctx->mem_target;
456 	tmp = ctx->basic_blocks;
457 	ctx->basic_blocks = ctx->basic_blocks->next;
458 	frags = (int)(total_size / new_size);
459 	ctx->stats[new_size].blocks++;
460 	ctx->stats[new_size].freefrags += frags;
461 	/*
462 	 * Set up a linked-list of blocks of size
463 	 * "new_size".
464 	 */
465 	curr = tmp;
466 	next = curr + new_size;
467 	total_size -= new_size;
468 	for (int i = 0; i < (frags - 1); i++) {
469 		((element *)curr)->next = (element *)next;
470 		curr = next;
471 		next += new_size;
472 		total_size -= new_size;
473 	}
474 	/*
475 	 * Add the remaining fragment of the basic block to a free list.
476 	 */
477 	total_size = rmsize(total_size);
478 	if (total_size > 0U) {
479 		((element *)next)->next = ctx->freelists[total_size];
480 		ctx->freelists[total_size] = (element *)next;
481 		ctx->stats[total_size].freefrags++;
482 	}
483 	/*
484 	 * curr is now pointing at the last block in the
485 	 * array.
486 	 */
487 	((element *)curr)->next = NULL;
488 	ctx->freelists[new_size] = tmp;
489 }
490 
491 static void *
mem_getunlocked(isc__mem_t * ctx,size_t size)492 mem_getunlocked(isc__mem_t *ctx, size_t size) {
493 	size_t new_size = quantize(size);
494 	void *ret;
495 
496 	if (new_size >= ctx->max_size) {
497 		/*
498 		 * memget() was called on something beyond our upper limit.
499 		 */
500 		ret = (ctx->memalloc)(size);
501 		ctx->total += size;
502 		ctx->inuse += size;
503 		ctx->stats[ctx->max_size].gets++;
504 		ctx->stats[ctx->max_size].totalgets++;
505 		ctx->malloced += size;
506 		if (ctx->malloced > ctx->maxmalloced) {
507 			ctx->maxmalloced = ctx->malloced;
508 		}
509 		/*
510 		 * If we don't set new_size to size, then the
511 		 * ISC_MEMFLAG_FILL code might write over bytes we don't
512 		 * own.
513 		 */
514 		new_size = size;
515 		goto done;
516 	}
517 	/*
518 	 * If there are no blocks in the free list for this size, get a chunk
519 	 * of memory and then break it up into "new_size"-sized blocks, adding
520 	 * them to the free list.
521 	 */
522 	if (ctx->freelists[new_size] == NULL) {
523 		more_frags(ctx, new_size);
524 	}
525 	INSIST(ctx->freelists[new_size] != NULL);
526 
527 	/*
528 	 * The free list uses the "rounded-up" size "new_size".
529 	 */
530 
531 	ret = ctx->freelists[new_size];
532 	ctx->freelists[new_size] = ctx->freelists[new_size]->next;
533 
534 	/*
535 	 * The stats[] uses the _actual_ "size" requested by the
536 	 * caller, with the caveat (in the code above) that "size" >= the
537 	 * max. size (max_size) ends up getting recorded as a call to
538 	 * max_size.
539 	 */
540 	ctx->stats[size].gets++;
541 	ctx->stats[size].totalgets++;
542 	ctx->stats[new_size].freefrags--;
543 	ctx->inuse += new_size;
544 
545 done:
546 	if (ISC_UNLIKELY((ctx->flags & ISC_MEMFLAG_FILL) != 0) &&
547 	    ISC_LIKELY(ret != NULL))
548 	{
549 		memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
550 	}
551 
552 	return (ret);
553 }
554 
555 #if ISC_MEM_CHECKOVERRUN
556 static void
check_overrun(void * mem,size_t size,size_t new_size)557 check_overrun(void *mem, size_t size, size_t new_size) {
558 	unsigned char *cp;
559 
560 	cp = (unsigned char *)mem;
561 	cp += size;
562 	while (size < new_size) {
563 		INSIST(*cp == 0xbe);
564 		cp++;
565 		size++;
566 	}
567 }
568 #endif /* if ISC_MEM_CHECKOVERRUN */
569 
570 /* coverity[+free : arg-1] */
571 static void
mem_putunlocked(isc__mem_t * ctx,void * mem,size_t size)572 mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) {
573 	size_t new_size = quantize(size);
574 
575 	if (new_size >= ctx->max_size) {
576 		/*
577 		 * memput() called on something beyond our upper limit.
578 		 */
579 		if (ISC_UNLIKELY((ctx->flags & ISC_MEMFLAG_FILL) != 0)) {
580 			memset(mem, 0xde, size); /* Mnemonic for "dead". */
581 		}
582 
583 		(ctx->memfree)(mem);
584 		INSIST(ctx->stats[ctx->max_size].gets != 0U);
585 		ctx->stats[ctx->max_size].gets--;
586 		INSIST(size <= ctx->inuse);
587 		ctx->inuse -= size;
588 		ctx->malloced -= size;
589 		return;
590 	}
591 
592 	if (ISC_UNLIKELY((ctx->flags & ISC_MEMFLAG_FILL) != 0)) {
593 #if ISC_MEM_CHECKOVERRUN
594 		check_overrun(mem, size, new_size);
595 #endif					     /* if ISC_MEM_CHECKOVERRUN */
596 		memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
597 	}
598 
599 	/*
600 	 * The free list uses the "rounded-up" size "new_size".
601 	 */
602 	((element *)mem)->next = ctx->freelists[new_size];
603 	ctx->freelists[new_size] = (element *)mem;
604 
605 	/*
606 	 * The stats[] uses the _actual_ "size" requested by the
607 	 * caller, with the caveat (in the code above) that "size" >= the
608 	 * max. size (max_size) ends up getting recorded as a call to
609 	 * max_size.
610 	 */
611 	INSIST(ctx->stats[size].gets != 0U);
612 	ctx->stats[size].gets--;
613 	ctx->stats[new_size].freefrags++;
614 	ctx->inuse -= new_size;
615 }
616 
617 /*!
618  * Perform a malloc, doing memory filling and overrun detection as necessary.
619  */
620 static void *
mem_get(isc__mem_t * ctx,size_t size)621 mem_get(isc__mem_t *ctx, size_t size) {
622 	char *ret;
623 
624 #if ISC_MEM_CHECKOVERRUN
625 	size += 1;
626 #endif /* if ISC_MEM_CHECKOVERRUN */
627 	ret = (ctx->memalloc)(size);
628 
629 	if (ISC_UNLIKELY((ctx->flags & ISC_MEMFLAG_FILL) != 0)) {
630 		if (ISC_LIKELY(ret != NULL)) {
631 			memset(ret, 0xbe, size); /* Mnemonic for "beef". */
632 		}
633 	}
634 #if ISC_MEM_CHECKOVERRUN
635 	else
636 	{
637 		if (ISC_LIKELY(ret != NULL)) {
638 			ret[size - 1] = 0xbe;
639 		}
640 	}
641 #endif /* if ISC_MEM_CHECKOVERRUN */
642 
643 	return (ret);
644 }
645 
646 /*!
647  * Perform a free, doing memory filling and overrun detection as necessary.
648  */
649 /* coverity[+free : arg-1] */
650 static void
mem_put(isc__mem_t * ctx,void * mem,size_t size)651 mem_put(isc__mem_t *ctx, void *mem, size_t size) {
652 #if ISC_MEM_CHECKOVERRUN
653 	INSIST(((unsigned char *)mem)[size] == 0xbe);
654 	size += 1;
655 #endif /* if ISC_MEM_CHECKOVERRUN */
656 	if (ISC_UNLIKELY((ctx->flags & ISC_MEMFLAG_FILL) != 0)) {
657 		memset(mem, 0xde, size); /* Mnemonic for "dead". */
658 	}
659 	(ctx->memfree)(mem);
660 }
661 
662 /*!
663  * Update internal counters after a memory get.
664  */
665 static void
mem_getstats(isc__mem_t * ctx,size_t size)666 mem_getstats(isc__mem_t *ctx, size_t size) {
667 	ctx->total += size;
668 	ctx->inuse += size;
669 
670 	if (size > ctx->max_size) {
671 		ctx->stats[ctx->max_size].gets++;
672 		ctx->stats[ctx->max_size].totalgets++;
673 	} else {
674 		ctx->stats[size].gets++;
675 		ctx->stats[size].totalgets++;
676 	}
677 
678 #if ISC_MEM_CHECKOVERRUN
679 	size += 1;
680 #endif /* if ISC_MEM_CHECKOVERRUN */
681 	ctx->malloced += size;
682 	if (ctx->malloced > ctx->maxmalloced) {
683 		ctx->maxmalloced = ctx->malloced;
684 	}
685 }
686 
687 /*!
688  * Update internal counters after a memory put.
689  */
690 static void
mem_putstats(isc__mem_t * ctx,void * ptr,size_t size)691 mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) {
692 	UNUSED(ptr);
693 
694 	INSIST(ctx->inuse >= size);
695 	ctx->inuse -= size;
696 
697 	if (size > ctx->max_size) {
698 		INSIST(ctx->stats[ctx->max_size].gets > 0U);
699 		ctx->stats[ctx->max_size].gets--;
700 	} else {
701 		INSIST(ctx->stats[size].gets > 0U);
702 		ctx->stats[size].gets--;
703 	}
704 #if ISC_MEM_CHECKOVERRUN
705 	size += 1;
706 #endif /* if ISC_MEM_CHECKOVERRUN */
707 	ctx->malloced -= size;
708 }
709 
710 /*
711  * Private.
712  */
713 
714 static void *
default_memalloc(size_t size)715 default_memalloc(size_t size) {
716 	void *ptr;
717 
718 	ptr = malloc(size);
719 
720 	/*
721 	 * If the space cannot be allocated, a null pointer is returned. If the
722 	 * size of the space requested is zero, the behavior is
723 	 * implementation-defined: either a null pointer is returned, or the
724 	 * behavior is as if the size were some nonzero value, except that the
725 	 * returned pointer shall not be used to access an object.
726 	 * [ISO9899 § 7.22.3]
727 	 *
728 	 * [ISO9899]
729 	 *   ISO/IEC WG 9899:2011: Programming languages - C.
730 	 *   International Organization for Standardization, Geneva,
731 	 * Switzerland.
732 	 *   http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf
733 	 */
734 
735 	if (ptr == NULL && size != 0) {
736 		char strbuf[ISC_STRERRORSIZE];
737 		strerror_r(errno, strbuf, sizeof(strbuf));
738 		isc_error_fatal(__FILE__, __LINE__, "malloc failed: %s",
739 				strbuf);
740 	}
741 
742 	return (ptr);
743 }
744 
745 static void
default_memfree(void * ptr)746 default_memfree(void *ptr) {
747 	free(ptr);
748 }
749 
750 static void
mem_initialize(void)751 mem_initialize(void) {
752 	isc_mutex_init(&contextslock);
753 	ISC_LIST_INIT(contexts);
754 	totallost = 0;
755 }
756 
757 void
isc__mem_initialize(void)758 isc__mem_initialize(void) {
759 	RUNTIME_CHECK(isc_once_do(&init_once, mem_initialize) == ISC_R_SUCCESS);
760 }
761 
762 static void
mem_shutdown(void)763 mem_shutdown(void) {
764 	isc__mem_checkdestroyed();
765 
766 	isc_mutex_destroy(&contextslock);
767 }
768 
769 void
isc__mem_shutdown(void)770 isc__mem_shutdown(void) {
771 	RUNTIME_CHECK(isc_once_do(&shut_once, mem_shutdown) == ISC_R_SUCCESS);
772 }
773 
774 static void
mem_create(isc_mem_t ** ctxp,unsigned int flags)775 mem_create(isc_mem_t **ctxp, unsigned int flags) {
776 	REQUIRE(ctxp != NULL && *ctxp == NULL);
777 #if __SANITIZE_ADDRESS__
778 	REQUIRE((flags & ISC_MEMFLAG_INTERNAL) == 0);
779 #endif
780 
781 	isc__mem_t *ctx;
782 
783 	isc_enable_constructors();
784 
785 	STATIC_ASSERT((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0,
786 		      "wrong alignment size");
787 
788 	ctx = (default_memalloc)(sizeof(*ctx));
789 
790 	isc_mutex_init(&ctx->lock);
791 
792 	ctx->max_size = DEF_MAX_SIZE;
793 	ctx->flags = flags;
794 	isc_refcount_init(&ctx->references, 1);
795 	memset(ctx->name, 0, sizeof(ctx->name));
796 	ctx->tag = NULL;
797 	ctx->total = 0;
798 	ctx->inuse = 0;
799 	ctx->maxinuse = 0;
800 	ctx->malloced = sizeof(*ctx);
801 	ctx->maxmalloced = sizeof(*ctx);
802 	ctx->hi_water = 0;
803 	ctx->lo_water = 0;
804 	ctx->hi_called = false;
805 	ctx->is_overmem = false;
806 	ctx->water = NULL;
807 	ctx->water_arg = NULL;
808 	ctx->common.impmagic = MEM_MAGIC;
809 	ctx->common.magic = ISCAPI_MCTX_MAGIC;
810 	ctx->common.methods = (isc_memmethods_t *)&memmethods;
811 	ctx->memalloc = default_memalloc;
812 	ctx->memfree = default_memfree;
813 	ctx->stats = NULL;
814 	ctx->checkfree = true;
815 #if ISC_MEM_TRACKLINES
816 	ctx->debuglist = NULL;
817 	ctx->debuglistcnt = 0;
818 #endif /* if ISC_MEM_TRACKLINES */
819 	ISC_LIST_INIT(ctx->pools);
820 	ctx->poolcnt = 0;
821 	ctx->freelists = NULL;
822 	ctx->basic_blocks = NULL;
823 	ctx->basic_table = NULL;
824 	ctx->basic_table_count = 0;
825 	ctx->basic_table_size = 0;
826 	ctx->lowest = NULL;
827 	ctx->highest = NULL;
828 
829 	ctx->stats =
830 		(ctx->memalloc)((ctx->max_size + 1) * sizeof(struct stats));
831 
832 	memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
833 	ctx->malloced += (ctx->max_size + 1) * sizeof(struct stats);
834 	ctx->maxmalloced += (ctx->max_size + 1) * sizeof(struct stats);
835 
836 	if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
837 		ctx->mem_target = DEF_MEM_TARGET;
838 		ctx->freelists =
839 			(ctx->memalloc)(ctx->max_size * sizeof(element *));
840 		memset(ctx->freelists, 0, ctx->max_size * sizeof(element *));
841 		ctx->malloced += ctx->max_size * sizeof(element *);
842 		ctx->maxmalloced += ctx->max_size * sizeof(element *);
843 	}
844 
845 #if ISC_MEM_TRACKLINES
846 	if (ISC_UNLIKELY((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0)) {
847 		unsigned int i;
848 
849 		ctx->debuglist = (ctx->memalloc)(
850 			(DEBUG_TABLE_COUNT * sizeof(debuglist_t)));
851 		for (i = 0; i < DEBUG_TABLE_COUNT; i++) {
852 			ISC_LIST_INIT(ctx->debuglist[i]);
853 		}
854 		ctx->malloced += DEBUG_TABLE_COUNT * sizeof(debuglist_t);
855 		ctx->maxmalloced += DEBUG_TABLE_COUNT * sizeof(debuglist_t);
856 	}
857 #endif /* if ISC_MEM_TRACKLINES */
858 
859 	LOCK(&contextslock);
860 	ISC_LIST_INITANDAPPEND(contexts, ctx, link);
861 	UNLOCK(&contextslock);
862 
863 	*ctxp = (isc_mem_t *)ctx;
864 }
865 
866 /*
867  * Public.
868  */
869 
870 static void
destroy(isc__mem_t * ctx)871 destroy(isc__mem_t *ctx) {
872 	unsigned int i;
873 
874 	LOCK(&contextslock);
875 	ISC_LIST_UNLINK(contexts, ctx, link);
876 	totallost += ctx->inuse;
877 	UNLOCK(&contextslock);
878 
879 	ctx->common.impmagic = 0;
880 	ctx->common.magic = 0;
881 
882 	INSIST(ISC_LIST_EMPTY(ctx->pools));
883 
884 #if ISC_MEM_TRACKLINES
885 	if (ISC_UNLIKELY(ctx->debuglist != NULL)) {
886 		debuglink_t *dl;
887 		for (i = 0; i < DEBUG_TABLE_COUNT; i++) {
888 			for (dl = ISC_LIST_HEAD(ctx->debuglist[i]); dl != NULL;
889 			     dl = ISC_LIST_HEAD(ctx->debuglist[i]))
890 			{
891 				if (ctx->checkfree && dl->ptr != NULL) {
892 					print_active(ctx, stderr);
893 				}
894 				INSIST(!ctx->checkfree || dl->ptr == NULL);
895 
896 				ISC_LIST_UNLINK(ctx->debuglist[i], dl, link);
897 				free(dl);
898 				ctx->malloced -= sizeof(*dl);
899 			}
900 		}
901 
902 		(ctx->memfree)(ctx->debuglist);
903 		ctx->malloced -= DEBUG_TABLE_COUNT * sizeof(debuglist_t);
904 	}
905 #endif /* if ISC_MEM_TRACKLINES */
906 
907 	if (ctx->checkfree) {
908 		for (i = 0; i <= ctx->max_size; i++) {
909 			if (ctx->stats[i].gets != 0U) {
910 				fprintf(stderr,
911 					"Failing assertion due to probable "
912 					"leaked memory in context %p (\"%s\") "
913 					"(stats[%u].gets == %lu).\n",
914 					ctx, ctx->name, i, ctx->stats[i].gets);
915 #if ISC_MEM_TRACKLINES
916 				print_active(ctx, stderr);
917 #endif /* if ISC_MEM_TRACKLINES */
918 				INSIST(ctx->stats[i].gets == 0U);
919 			}
920 		}
921 	}
922 
923 	(ctx->memfree)(ctx->stats);
924 	ctx->malloced -= (ctx->max_size + 1) * sizeof(struct stats);
925 
926 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
927 		for (i = 0; i < ctx->basic_table_count; i++) {
928 			(ctx->memfree)(ctx->basic_table[i]);
929 			ctx->malloced -= NUM_BASIC_BLOCKS * ctx->mem_target;
930 		}
931 		(ctx->memfree)(ctx->freelists);
932 		ctx->malloced -= ctx->max_size * sizeof(element *);
933 		if (ctx->basic_table != NULL) {
934 			(ctx->memfree)(ctx->basic_table);
935 			ctx->malloced -= ctx->basic_table_size *
936 					 sizeof(unsigned char *);
937 		}
938 	}
939 
940 	isc_mutex_destroy(&ctx->lock);
941 
942 	ctx->malloced -= sizeof(*ctx);
943 	if (ctx->checkfree) {
944 		INSIST(ctx->malloced == 0);
945 	}
946 	(ctx->memfree)(ctx);
947 }
948 
949 void
isc_mem_attach(isc_mem_t * source0,isc_mem_t ** targetp)950 isc_mem_attach(isc_mem_t *source0, isc_mem_t **targetp) {
951 	REQUIRE(VALID_CONTEXT(source0));
952 	REQUIRE(targetp != NULL && *targetp == NULL);
953 
954 	isc__mem_t *source = (isc__mem_t *)source0;
955 
956 	isc_refcount_increment(&source->references);
957 
958 	*targetp = (isc_mem_t *)source;
959 }
960 
961 void
isc_mem_detach(isc_mem_t ** ctxp)962 isc_mem_detach(isc_mem_t **ctxp) {
963 	REQUIRE(ctxp != NULL && VALID_CONTEXT(*ctxp));
964 
965 	isc__mem_t *ctx = (isc__mem_t *)*ctxp;
966 	*ctxp = NULL;
967 
968 	if (isc_refcount_decrement(&ctx->references) == 1) {
969 		isc_refcount_destroy(&ctx->references);
970 		destroy(ctx);
971 	}
972 }
973 
974 /*
975  * isc_mem_putanddetach() is the equivalent of:
976  *
977  * mctx = NULL;
978  * isc_mem_attach(ptr->mctx, &mctx);
979  * isc_mem_detach(&ptr->mctx);
980  * isc_mem_put(mctx, ptr, sizeof(*ptr);
981  * isc_mem_detach(&mctx);
982  */
983 
984 void
isc___mem_putanddetach(isc_mem_t ** ctxp,void * ptr,size_t size FLARG)985 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
986 	REQUIRE(ctxp != NULL && VALID_CONTEXT(*ctxp));
987 	REQUIRE(ptr != NULL);
988 
989 	isc__mem_t *ctx = (isc__mem_t *)*ctxp;
990 	*ctxp = NULL;
991 
992 	if (ISC_UNLIKELY((isc_mem_debugging &
993 			  (ISC_MEM_DEBUGSIZE | ISC_MEM_DEBUGCTX)) != 0))
994 	{
995 		if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
996 			size_info *si = &(((size_info *)ptr)[-1]);
997 			size_t oldsize = si->u.size - ALIGNMENT_SIZE;
998 			if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
999 				oldsize -= ALIGNMENT_SIZE;
1000 			}
1001 			INSIST(oldsize == size);
1002 		}
1003 		isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
1004 
1005 		goto destroy;
1006 	}
1007 
1008 	MCTXLOCK(ctx);
1009 
1010 	DELETE_TRACE(ctx, ptr, size, file, line);
1011 
1012 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1013 		mem_putunlocked(ctx, ptr, size);
1014 	} else {
1015 		mem_putstats(ctx, ptr, size);
1016 		mem_put(ctx, ptr, size);
1017 	}
1018 	MCTXUNLOCK(ctx);
1019 
1020 destroy:
1021 	if (isc_refcount_decrement(&ctx->references) == 1) {
1022 		isc_refcount_destroy(&ctx->references);
1023 		destroy(ctx);
1024 	}
1025 }
1026 
1027 void
isc_mem_destroy(isc_mem_t ** ctxp)1028 isc_mem_destroy(isc_mem_t **ctxp) {
1029 	/*
1030 	 * This routine provides legacy support for callers who use mctxs
1031 	 * without attaching/detaching.
1032 	 */
1033 
1034 	REQUIRE(ctxp != NULL && VALID_CONTEXT(*ctxp));
1035 
1036 	isc__mem_t *ctx = (isc__mem_t *)*ctxp;
1037 
1038 #if ISC_MEM_TRACKLINES
1039 	if (isc_refcount_decrement(&ctx->references) > 1) {
1040 		print_active(ctx, stderr);
1041 	}
1042 #else  /* if ISC_MEM_TRACKLINES */
1043 	isc_refcount_decrementz(&ctx->references);
1044 #endif /* if ISC_MEM_TRACKLINES */
1045 	isc_refcount_destroy(&ctx->references);
1046 	destroy(ctx);
1047 
1048 	*ctxp = NULL;
1049 }
1050 
1051 void *
isc___mem_get(isc_mem_t * ctx0,size_t size FLARG)1052 isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
1053 	REQUIRE(VALID_CONTEXT(ctx0));
1054 
1055 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1056 	void *ptr;
1057 	bool call_water = false;
1058 
1059 	if (ISC_UNLIKELY((isc_mem_debugging &
1060 			  (ISC_MEM_DEBUGSIZE | ISC_MEM_DEBUGCTX)) != 0))
1061 	{
1062 		return (isc__mem_allocate(ctx0, size FLARG_PASS));
1063 	}
1064 
1065 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1066 		MCTXLOCK(ctx);
1067 		ptr = mem_getunlocked(ctx, size);
1068 	} else {
1069 		ptr = mem_get(ctx, size);
1070 		MCTXLOCK(ctx);
1071 		if (ptr != NULL) {
1072 			mem_getstats(ctx, size);
1073 		}
1074 	}
1075 
1076 	ADD_TRACE(ctx, ptr, size, file, line);
1077 
1078 	if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water) {
1079 		ctx->is_overmem = true;
1080 		if (!ctx->hi_called) {
1081 			call_water = true;
1082 		}
1083 	}
1084 	if (ctx->inuse > ctx->maxinuse) {
1085 		ctx->maxinuse = ctx->inuse;
1086 		if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1087 		    (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1088 		{
1089 			fprintf(stderr, "maxinuse = %lu\n",
1090 				(unsigned long)ctx->inuse);
1091 		}
1092 	}
1093 	MCTXUNLOCK(ctx);
1094 
1095 	if (call_water && (ctx->water != NULL)) {
1096 		(ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1097 	}
1098 
1099 	return (ptr);
1100 }
1101 
1102 void
isc___mem_put(isc_mem_t * ctx0,void * ptr,size_t size FLARG)1103 isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1104 	REQUIRE(VALID_CONTEXT(ctx0));
1105 	REQUIRE(ptr != NULL);
1106 
1107 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1108 	bool call_water = false;
1109 	size_info *si;
1110 	size_t oldsize;
1111 
1112 	if (ISC_UNLIKELY((isc_mem_debugging &
1113 			  (ISC_MEM_DEBUGSIZE | ISC_MEM_DEBUGCTX)) != 0))
1114 	{
1115 		if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1116 			si = &(((size_info *)ptr)[-1]);
1117 			oldsize = si->u.size - ALIGNMENT_SIZE;
1118 			if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1119 				oldsize -= ALIGNMENT_SIZE;
1120 			}
1121 			INSIST(oldsize == size);
1122 		}
1123 		isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
1124 		return;
1125 	}
1126 
1127 	MCTXLOCK(ctx);
1128 
1129 	DELETE_TRACE(ctx, ptr, size, file, line);
1130 
1131 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1132 		mem_putunlocked(ctx, ptr, size);
1133 	} else {
1134 		mem_putstats(ctx, ptr, size);
1135 		mem_put(ctx, ptr, size);
1136 	}
1137 
1138 	/*
1139 	 * The check against ctx->lo_water == 0 is for the condition
1140 	 * when the context was pushed over hi_water but then had
1141 	 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1142 	 */
1143 	if ((ctx->inuse < ctx->lo_water) || (ctx->lo_water == 0U)) {
1144 		ctx->is_overmem = false;
1145 		if (ctx->hi_called) {
1146 			call_water = true;
1147 		}
1148 	}
1149 
1150 	MCTXUNLOCK(ctx);
1151 
1152 	if (call_water && (ctx->water != NULL)) {
1153 		(ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1154 	}
1155 }
1156 
1157 void
isc_mem_waterack(isc_mem_t * ctx0,int flag)1158 isc_mem_waterack(isc_mem_t *ctx0, int flag) {
1159 	REQUIRE(VALID_CONTEXT(ctx0));
1160 
1161 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1162 
1163 	MCTXLOCK(ctx);
1164 	if (flag == ISC_MEM_LOWATER) {
1165 		ctx->hi_called = false;
1166 	} else if (flag == ISC_MEM_HIWATER) {
1167 		ctx->hi_called = true;
1168 	}
1169 	MCTXUNLOCK(ctx);
1170 }
1171 
1172 #if ISC_MEM_TRACKLINES
1173 static void
print_active(isc__mem_t * mctx,FILE * out)1174 print_active(isc__mem_t *mctx, FILE *out) {
1175 	if (mctx->debuglist != NULL) {
1176 		debuglink_t *dl;
1177 		unsigned int i;
1178 		bool found;
1179 
1180 		fputs("Dump of all outstanding memory allocations:\n", out);
1181 		found = false;
1182 		for (i = 0; i < DEBUG_TABLE_COUNT; i++) {
1183 			dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1184 
1185 			if (dl != NULL) {
1186 				found = true;
1187 			}
1188 
1189 			while (dl != NULL) {
1190 				if (dl->ptr != NULL) {
1191 					fprintf(out,
1192 						"\tptr %p size %zu file %s "
1193 						"line %u\n",
1194 						dl->ptr, dl->size, dl->file,
1195 						dl->line);
1196 				}
1197 				dl = ISC_LIST_NEXT(dl, link);
1198 			}
1199 		}
1200 
1201 		if (!found) {
1202 			fputs("\tNone.\n", out);
1203 		}
1204 	}
1205 }
1206 #endif /* if ISC_MEM_TRACKLINES */
1207 
1208 /*
1209  * Print the stats[] on the stream "out" with suitable formatting.
1210  */
1211 void
isc_mem_stats(isc_mem_t * ctx0,FILE * out)1212 isc_mem_stats(isc_mem_t *ctx0, FILE *out) {
1213 	REQUIRE(VALID_CONTEXT(ctx0));
1214 
1215 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1216 	size_t i;
1217 	const struct stats *s;
1218 	const isc__mempool_t *pool;
1219 
1220 	MCTXLOCK(ctx);
1221 
1222 	for (i = 0; i <= ctx->max_size; i++) {
1223 		s = &ctx->stats[i];
1224 
1225 		if (s->totalgets == 0U && s->gets == 0U) {
1226 			continue;
1227 		}
1228 		fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1229 			(i == ctx->max_size) ? ">=" : "  ", (unsigned long)i,
1230 			s->totalgets, s->gets);
1231 		if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1232 		    (s->blocks != 0U || s->freefrags != 0U))
1233 		{
1234 			fprintf(out, " (%lu bl, %lu ff)", s->blocks,
1235 				s->freefrags);
1236 		}
1237 		fputc('\n', out);
1238 	}
1239 
1240 	/*
1241 	 * Note that since a pool can be locked now, these stats might be
1242 	 * somewhat off if the pool is in active use at the time the stats
1243 	 * are dumped.  The link fields are protected by the isc_mem_t's
1244 	 * lock, however, so walking this list and extracting integers from
1245 	 * stats fields is always safe.
1246 	 */
1247 	pool = ISC_LIST_HEAD(ctx->pools);
1248 	if (pool != NULL) {
1249 		fputs("[Pool statistics]\n", out);
1250 		fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1251 			"name", "size", "maxalloc", "allocated", "freecount",
1252 			"freemax", "fillcount", "gets", "L");
1253 	}
1254 	while (pool != NULL) {
1255 		fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1256 #if ISC_MEMPOOL_NAMES
1257 			pool->name,
1258 #else  /* if ISC_MEMPOOL_NAMES */
1259 			"(not tracked)",
1260 #endif /* if ISC_MEMPOOL_NAMES */
1261 			(unsigned long)pool->size, pool->maxalloc,
1262 			pool->allocated, pool->freecount, pool->freemax,
1263 			pool->fillcount, pool->gets, "N");
1264 		pool = ISC_LIST_NEXT(pool, link);
1265 	}
1266 
1267 #if ISC_MEM_TRACKLINES
1268 	print_active(ctx, out);
1269 #endif /* if ISC_MEM_TRACKLINES */
1270 
1271 	MCTXUNLOCK(ctx);
1272 }
1273 
1274 /*
1275  * Replacements for malloc() and free() -- they implicitly remember the
1276  * size of the object allocated (with some additional overhead).
1277  */
1278 
1279 static void *
mem_allocateunlocked(isc_mem_t * ctx0,size_t size)1280 mem_allocateunlocked(isc_mem_t *ctx0, size_t size) {
1281 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1282 	size_info *si;
1283 
1284 	size += ALIGNMENT_SIZE;
1285 	if (ISC_UNLIKELY((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)) {
1286 		size += ALIGNMENT_SIZE;
1287 	}
1288 
1289 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1290 		si = mem_getunlocked(ctx, size);
1291 	} else {
1292 		si = mem_get(ctx, size);
1293 	}
1294 
1295 	if (ISC_UNLIKELY((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)) {
1296 		si->u.ctx = ctx;
1297 		si++;
1298 	}
1299 	si->u.size = size;
1300 	return (&si[1]);
1301 }
1302 
1303 void *
isc___mem_allocate(isc_mem_t * ctx0,size_t size FLARG)1304 isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
1305 	REQUIRE(VALID_CONTEXT(ctx0));
1306 
1307 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1308 	size_info *si;
1309 	bool call_water = false;
1310 
1311 	MCTXLOCK(ctx);
1312 	si = mem_allocateunlocked((isc_mem_t *)ctx, size);
1313 	if (((ctx->flags & ISC_MEMFLAG_INTERNAL) == 0)) {
1314 		mem_getstats(ctx, si[-1].u.size);
1315 	}
1316 
1317 	ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1318 	if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1319 	    !ctx->is_overmem)
1320 	{
1321 		ctx->is_overmem = true;
1322 	}
1323 
1324 	if (ctx->hi_water != 0U && !ctx->hi_called &&
1325 	    ctx->inuse > ctx->hi_water)
1326 	{
1327 		ctx->hi_called = true;
1328 		call_water = true;
1329 	}
1330 	if (ctx->inuse > ctx->maxinuse) {
1331 		ctx->maxinuse = ctx->inuse;
1332 		if (ISC_UNLIKELY(ctx->hi_water != 0U &&
1333 				 ctx->inuse > ctx->hi_water &&
1334 				 (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0))
1335 		{
1336 			fprintf(stderr, "maxinuse = %lu\n",
1337 				(unsigned long)ctx->inuse);
1338 		}
1339 	}
1340 	MCTXUNLOCK(ctx);
1341 
1342 	if (call_water) {
1343 		(ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1344 	}
1345 
1346 	return (si);
1347 }
1348 
1349 void *
isc___mem_reallocate(isc_mem_t * ctx0,void * ptr,size_t size FLARG)1350 isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1351 	REQUIRE(VALID_CONTEXT(ctx0));
1352 
1353 	void *new_ptr = NULL;
1354 	size_t oldsize, copysize;
1355 
1356 	/*
1357 	 * This function emulates the realloc(3) standard library function:
1358 	 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1359 	 *   as much of the old contents to the new buffer and free the old one.
1360 	 *   Note that when allocation fails the original pointer is intact;
1361 	 *   the caller must free it.
1362 	 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1363 	 * - this function returns:
1364 	 *     pointer to the newly allocated memory, or
1365 	 *     NULL if allocation fails or doesn't happen.
1366 	 */
1367 	if (size > 0U) {
1368 		new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS);
1369 		if (new_ptr != NULL && ptr != NULL) {
1370 			oldsize = (((size_info *)ptr)[-1]).u.size;
1371 			INSIST(oldsize >= ALIGNMENT_SIZE);
1372 			oldsize -= ALIGNMENT_SIZE;
1373 			if (ISC_UNLIKELY((isc_mem_debugging &
1374 					  ISC_MEM_DEBUGCTX) != 0))
1375 			{
1376 				INSIST(oldsize >= ALIGNMENT_SIZE);
1377 				oldsize -= ALIGNMENT_SIZE;
1378 			}
1379 			copysize = (oldsize > size) ? size : oldsize;
1380 			memmove(new_ptr, ptr, copysize);
1381 			isc__mem_free(ctx0, ptr FLARG_PASS);
1382 		}
1383 	} else if (ptr != NULL) {
1384 		isc__mem_free(ctx0, ptr FLARG_PASS);
1385 	}
1386 
1387 	return (new_ptr);
1388 }
1389 
1390 void
isc___mem_free(isc_mem_t * ctx0,void * ptr FLARG)1391 isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
1392 	REQUIRE(VALID_CONTEXT(ctx0));
1393 	REQUIRE(ptr != NULL);
1394 
1395 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1396 	size_info *si;
1397 	size_t size;
1398 	bool call_water = false;
1399 
1400 	if (ISC_UNLIKELY((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)) {
1401 		si = &(((size_info *)ptr)[-2]);
1402 		REQUIRE(si->u.ctx == ctx);
1403 		size = si[1].u.size;
1404 	} else {
1405 		si = &(((size_info *)ptr)[-1]);
1406 		size = si->u.size;
1407 	}
1408 
1409 	MCTXLOCK(ctx);
1410 
1411 	DELETE_TRACE(ctx, ptr, size, file, line);
1412 
1413 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1414 		mem_putunlocked(ctx, si, size);
1415 	} else {
1416 		mem_putstats(ctx, si, size);
1417 		mem_put(ctx, si, size);
1418 	}
1419 
1420 	/*
1421 	 * The check against ctx->lo_water == 0 is for the condition
1422 	 * when the context was pushed over hi_water but then had
1423 	 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1424 	 */
1425 	if (ctx->is_overmem &&
1426 	    (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U))
1427 	{
1428 		ctx->is_overmem = false;
1429 	}
1430 
1431 	if (ctx->hi_called &&
1432 	    (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U))
1433 	{
1434 		ctx->hi_called = false;
1435 
1436 		if (ctx->water != NULL) {
1437 			call_water = true;
1438 		}
1439 	}
1440 	MCTXUNLOCK(ctx);
1441 
1442 	if (call_water) {
1443 		(ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1444 	}
1445 }
1446 
1447 /*
1448  * Other useful things.
1449  */
1450 
1451 char *
isc___mem_strdup(isc_mem_t * mctx0,const char * s FLARG)1452 isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
1453 	REQUIRE(VALID_CONTEXT(mctx0));
1454 	REQUIRE(s != NULL);
1455 
1456 	isc__mem_t *mctx = (isc__mem_t *)mctx0;
1457 	size_t len;
1458 	char *ns;
1459 
1460 	len = strlen(s) + 1;
1461 
1462 	ns = isc__mem_allocate((isc_mem_t *)mctx, len FLARG_PASS);
1463 
1464 	if (ns != NULL) {
1465 		strlcpy(ns, s, len);
1466 	}
1467 
1468 	return (ns);
1469 }
1470 
1471 char *
isc___mem_strndup(isc_mem_t * mctx0,const char * s,size_t size FLARG)1472 isc___mem_strndup(isc_mem_t *mctx0, const char *s, size_t size FLARG) {
1473 	REQUIRE(VALID_CONTEXT(mctx0));
1474 	REQUIRE(s != NULL);
1475 
1476 	isc__mem_t *mctx = (isc__mem_t *)mctx0;
1477 	size_t len;
1478 	char *ns;
1479 
1480 	len = strlen(s) + 1;
1481 	if (len > size) {
1482 		len = size;
1483 	}
1484 
1485 	ns = isc__mem_allocate((isc_mem_t *)mctx, len FLARG_PASS);
1486 
1487 	if (ns != NULL) {
1488 		strlcpy(ns, s, len);
1489 	}
1490 
1491 	return (ns);
1492 }
1493 
1494 void
isc_mem_setdestroycheck(isc_mem_t * ctx0,bool flag)1495 isc_mem_setdestroycheck(isc_mem_t *ctx0, bool flag) {
1496 	REQUIRE(VALID_CONTEXT(ctx0));
1497 
1498 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1499 
1500 	MCTXLOCK(ctx);
1501 
1502 	ctx->checkfree = flag;
1503 
1504 	MCTXUNLOCK(ctx);
1505 }
1506 
1507 size_t
isc_mem_inuse(isc_mem_t * ctx0)1508 isc_mem_inuse(isc_mem_t *ctx0) {
1509 	REQUIRE(VALID_CONTEXT(ctx0));
1510 
1511 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1512 	size_t inuse;
1513 
1514 	MCTXLOCK(ctx);
1515 
1516 	inuse = ctx->inuse;
1517 
1518 	MCTXUNLOCK(ctx);
1519 
1520 	return (inuse);
1521 }
1522 
1523 size_t
isc_mem_maxinuse(isc_mem_t * ctx0)1524 isc_mem_maxinuse(isc_mem_t *ctx0) {
1525 	REQUIRE(VALID_CONTEXT(ctx0));
1526 
1527 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1528 	size_t maxinuse;
1529 
1530 	MCTXLOCK(ctx);
1531 
1532 	maxinuse = ctx->maxinuse;
1533 
1534 	MCTXUNLOCK(ctx);
1535 
1536 	return (maxinuse);
1537 }
1538 
1539 size_t
isc_mem_total(isc_mem_t * ctx0)1540 isc_mem_total(isc_mem_t *ctx0) {
1541 	REQUIRE(VALID_CONTEXT(ctx0));
1542 
1543 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1544 	size_t total;
1545 
1546 	MCTXLOCK(ctx);
1547 
1548 	total = ctx->total;
1549 
1550 	MCTXUNLOCK(ctx);
1551 
1552 	return (total);
1553 }
1554 
1555 void
isc_mem_setwater(isc_mem_t * ctx0,isc_mem_water_t water,void * water_arg,size_t hiwater,size_t lowater)1556 isc_mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg,
1557 		 size_t hiwater, size_t lowater) {
1558 	REQUIRE(VALID_CONTEXT(ctx0));
1559 	REQUIRE(hiwater >= lowater);
1560 
1561 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1562 	bool callwater = false;
1563 	isc_mem_water_t oldwater;
1564 	void *oldwater_arg;
1565 
1566 	MCTXLOCK(ctx);
1567 	oldwater = ctx->water;
1568 	oldwater_arg = ctx->water_arg;
1569 	if (water == NULL) {
1570 		callwater = ctx->hi_called;
1571 		ctx->water = NULL;
1572 		ctx->water_arg = NULL;
1573 		ctx->hi_water = 0;
1574 		ctx->lo_water = 0;
1575 	} else {
1576 		if (ctx->hi_called &&
1577 		    (ctx->water != water || ctx->water_arg != water_arg ||
1578 		     ctx->inuse < lowater || lowater == 0U))
1579 		{
1580 			callwater = true;
1581 		}
1582 		ctx->water = water;
1583 		ctx->water_arg = water_arg;
1584 		ctx->hi_water = hiwater;
1585 		ctx->lo_water = lowater;
1586 	}
1587 	MCTXUNLOCK(ctx);
1588 
1589 	if (callwater && oldwater != NULL) {
1590 		(oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1591 	}
1592 }
1593 
1594 ISC_NO_SANITIZE_THREAD bool
isc_mem_isovermem(isc_mem_t * ctx0)1595 isc_mem_isovermem(isc_mem_t *ctx0) {
1596 	REQUIRE(VALID_CONTEXT(ctx0));
1597 
1598 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1599 
1600 	/*
1601 	 * We don't bother to lock the context because 100% accuracy isn't
1602 	 * necessary (and even if we locked the context the returned value
1603 	 * could be different from the actual state when it's used anyway)
1604 	 */
1605 	return (ctx->is_overmem);
1606 }
1607 
1608 void
isc_mem_setname(isc_mem_t * ctx0,const char * name,void * tag)1609 isc_mem_setname(isc_mem_t *ctx0, const char *name, void *tag) {
1610 	REQUIRE(VALID_CONTEXT(ctx0));
1611 
1612 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1613 
1614 	LOCK(&ctx->lock);
1615 	strlcpy(ctx->name, name, sizeof(ctx->name));
1616 	ctx->tag = tag;
1617 	UNLOCK(&ctx->lock);
1618 }
1619 
1620 const char *
isc_mem_getname(isc_mem_t * ctx0)1621 isc_mem_getname(isc_mem_t *ctx0) {
1622 	REQUIRE(VALID_CONTEXT(ctx0));
1623 
1624 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1625 
1626 	if (ctx->name[0] == 0) {
1627 		return ("");
1628 	}
1629 
1630 	return (ctx->name);
1631 }
1632 
1633 void *
isc_mem_gettag(isc_mem_t * ctx0)1634 isc_mem_gettag(isc_mem_t *ctx0) {
1635 	REQUIRE(VALID_CONTEXT(ctx0));
1636 
1637 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1638 
1639 	return (ctx->tag);
1640 }
1641 
1642 /*
1643  * Memory pool stuff
1644  */
1645 
1646 void
isc_mempool_create(isc_mem_t * mctx0,size_t size,isc_mempool_t ** mpctxp)1647 isc_mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
1648 	REQUIRE(VALID_CONTEXT(mctx0));
1649 	REQUIRE(size > 0U);
1650 	REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1651 
1652 	isc__mem_t *mctx = (isc__mem_t *)mctx0;
1653 	isc__mempool_t *mpctx;
1654 
1655 	/*
1656 	 * Allocate space for this pool, initialize values, and if all works
1657 	 * well, attach to the memory context.
1658 	 */
1659 	mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t));
1660 
1661 	mpctx->common.impmagic = MEMPOOL_MAGIC;
1662 	mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
1663 	mpctx->mctx = NULL;
1664 	isc_mem_attach((isc_mem_t *)mctx, (isc_mem_t **)&mpctx->mctx);
1665 	/*
1666 	 * Mempools are stored as a linked list of element.
1667 	 */
1668 	if (size < sizeof(element)) {
1669 		size = sizeof(element);
1670 	}
1671 	mpctx->size = size;
1672 	mpctx->maxalloc = UINT_MAX;
1673 	mpctx->allocated = 0;
1674 	mpctx->freecount = 0;
1675 	mpctx->freemax = 1;
1676 	mpctx->fillcount = 1;
1677 	mpctx->gets = 0;
1678 #if ISC_MEMPOOL_NAMES
1679 	mpctx->name[0] = 0;
1680 #endif /* if ISC_MEMPOOL_NAMES */
1681 	mpctx->items = NULL;
1682 
1683 	*mpctxp = (isc_mempool_t *)mpctx;
1684 
1685 	MCTXLOCK(mctx);
1686 	ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1687 	mctx->poolcnt++;
1688 	MCTXUNLOCK(mctx);
1689 }
1690 
1691 void
isc_mempool_setname(isc_mempool_t * mpctx0,const char * name)1692 isc_mempool_setname(isc_mempool_t *mpctx0, const char *name) {
1693 	REQUIRE(VALID_MEMPOOL(mpctx0));
1694 	REQUIRE(name != NULL);
1695 
1696 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1697 
1698 #if ISC_MEMPOOL_NAMES
1699 	strlcpy(mpctx->name, name, sizeof(mpctx->name));
1700 #else  /* if ISC_MEMPOOL_NAMES */
1701 	UNUSED(mpctx);
1702 	UNUSED(name);
1703 #endif /* if ISC_MEMPOOL_NAMES */
1704 }
1705 
1706 void
isc_mempool_destroy(isc_mempool_t ** mpctxp)1707 isc_mempool_destroy(isc_mempool_t **mpctxp) {
1708 	REQUIRE(mpctxp != NULL);
1709 	REQUIRE(VALID_MEMPOOL(*mpctxp));
1710 
1711 	isc__mempool_t *mpctx;
1712 	isc__mem_t *mctx;
1713 	element *item;
1714 
1715 	mpctx = (isc__mempool_t *)*mpctxp;
1716 #if ISC_MEMPOOL_NAMES
1717 	if (mpctx->allocated > 0) {
1718 		UNEXPECTED_ERROR(__FILE__, __LINE__,
1719 				 "isc_mempool_destroy(): mempool %s "
1720 				 "leaked memory",
1721 				 mpctx->name);
1722 	}
1723 #endif /* if ISC_MEMPOOL_NAMES */
1724 	REQUIRE(mpctx->allocated == 0);
1725 
1726 	mctx = mpctx->mctx;
1727 
1728 	/*
1729 	 * Return any items on the free list
1730 	 */
1731 	MCTXLOCK(mctx);
1732 	while (mpctx->items != NULL) {
1733 		INSIST(mpctx->freecount > 0);
1734 		mpctx->freecount--;
1735 		item = mpctx->items;
1736 		mpctx->items = item->next;
1737 		mem_putstats(mctx, item, mpctx->size);
1738 		mem_put(mctx, item, mpctx->size);
1739 	}
1740 	MCTXUNLOCK(mctx);
1741 
1742 	/*
1743 	 * Remove our linked list entry from the memory context.
1744 	 */
1745 	MCTXLOCK(mctx);
1746 	ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1747 	mctx->poolcnt--;
1748 	MCTXUNLOCK(mctx);
1749 
1750 	mpctx->common.impmagic = 0;
1751 	mpctx->common.magic = 0;
1752 
1753 	isc_mem_putanddetach((isc_mem_t **)&mpctx->mctx, mpctx,
1754 			     sizeof(isc__mempool_t));
1755 
1756 	*mpctxp = NULL;
1757 }
1758 
1759 #if __SANITIZE_ADDRESS__
1760 void *
isc__mempool_get(isc_mempool_t * mpctx0 FLARG)1761 isc__mempool_get(isc_mempool_t *mpctx0 FLARG) {
1762 	void *item = NULL;
1763 
1764 	REQUIRE(VALID_MEMPOOL(mpctx0));
1765 
1766 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1767 	isc_mem_t *mctx = (isc_mem_t *)mpctx->mctx;
1768 
1769 	/*
1770 	 * Don't let the caller go over quota
1771 	 */
1772 	if (ISC_UNLIKELY(mpctx->allocated >= mpctx->maxalloc)) {
1773 		goto out;
1774 	}
1775 
1776 	item = isc__mem_get(mctx, mpctx->size FLARG_PASS);
1777 	mpctx->gets++;
1778 	mpctx->allocated++;
1779 
1780 out:
1781 	return (item);
1782 }
1783 
1784 void
isc__mempool_put(isc_mempool_t * mpctx0,void * mem FLARG)1785 isc__mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
1786 	REQUIRE(VALID_MEMPOOL(mpctx0));
1787 
1788 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1789 	isc_mem_t *mctx = (isc_mem_t *)mpctx->mctx;
1790 
1791 	REQUIRE(mem != NULL);
1792 
1793 	INSIST(mpctx->allocated > 0);
1794 	mpctx->allocated--;
1795 
1796 	isc__mem_put(mctx, mem, mpctx->size FLARG_PASS);
1797 }
1798 
1799 #else /* __SANITIZE_ADDRESS__ */
1800 void *
isc__mempool_get(isc_mempool_t * mpctx0 FLARG)1801 isc__mempool_get(isc_mempool_t *mpctx0 FLARG) {
1802 	REQUIRE(VALID_MEMPOOL(mpctx0));
1803 
1804 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1805 	element *item;
1806 	isc__mem_t *mctx;
1807 	unsigned int i;
1808 
1809 	mctx = mpctx->mctx;
1810 
1811 	/*
1812 	 * Don't let the caller go over quota
1813 	 */
1814 	if (ISC_UNLIKELY(mpctx->allocated >= mpctx->maxalloc)) {
1815 		item = NULL;
1816 		goto out;
1817 	}
1818 
1819 	if (ISC_UNLIKELY(mpctx->items == NULL)) {
1820 		/*
1821 		 * We need to dip into the well.  Lock the memory context
1822 		 * here and fill up our free list.
1823 		 */
1824 		MCTXLOCK(mctx);
1825 		for (i = 0; i < mpctx->fillcount; i++) {
1826 			item = mem_get(mctx, mpctx->size);
1827 			mem_getstats(mctx, mpctx->size);
1828 			item->next = mpctx->items;
1829 			mpctx->items = item;
1830 			mpctx->freecount++;
1831 		}
1832 		MCTXUNLOCK(mctx);
1833 	}
1834 
1835 	/*
1836 	 * If we didn't get any items, return NULL.
1837 	 */
1838 	item = mpctx->items;
1839 	if (ISC_UNLIKELY(item == NULL)) {
1840 		goto out;
1841 	}
1842 
1843 	mpctx->items = item->next;
1844 	INSIST(mpctx->freecount > 0);
1845 	mpctx->freecount--;
1846 	mpctx->gets++;
1847 	mpctx->allocated++;
1848 
1849 out:
1850 #if ISC_MEM_TRACKLINES
1851 	if (ISC_UNLIKELY(((isc_mem_debugging & TRACE_OR_RECORD) != 0) &&
1852 			 item != NULL))
1853 	{
1854 		MCTXLOCK(mctx);
1855 		ADD_TRACE(mctx, item, mpctx->size, file, line);
1856 		MCTXUNLOCK(mctx);
1857 	}
1858 #endif /* ISC_MEM_TRACKLINES */
1859 
1860 	return (item);
1861 }
1862 
1863 /* coverity[+free : arg-1] */
1864 void
isc__mempool_put(isc_mempool_t * mpctx0,void * mem FLARG)1865 isc__mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
1866 	REQUIRE(VALID_MEMPOOL(mpctx0));
1867 	REQUIRE(mem != NULL);
1868 
1869 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1870 	isc__mem_t *mctx = mpctx->mctx;
1871 	element *item;
1872 
1873 	INSIST(mpctx->allocated > 0);
1874 	mpctx->allocated--;
1875 
1876 #if ISC_MEM_TRACKLINES
1877 	if (ISC_UNLIKELY((isc_mem_debugging & TRACE_OR_RECORD) != 0)) {
1878 		MCTXLOCK(mctx);
1879 		DELETE_TRACE(mctx, mem, mpctx->size, file, line);
1880 		MCTXUNLOCK(mctx);
1881 	}
1882 #endif /* ISC_MEM_TRACKLINES */
1883 
1884 	/*
1885 	 * If our free list is full, return this to the mctx directly.
1886 	 */
1887 	if (mpctx->freecount >= mpctx->freemax) {
1888 		MCTXLOCK(mctx);
1889 		mem_putstats(mctx, mem, mpctx->size);
1890 		mem_put(mctx, mem, mpctx->size);
1891 		MCTXUNLOCK(mctx);
1892 		return;
1893 	}
1894 
1895 	/*
1896 	 * Otherwise, attach it to our free list and bump the counter.
1897 	 */
1898 	mpctx->freecount++;
1899 	item = (element *)mem;
1900 	item->next = mpctx->items;
1901 	mpctx->items = item;
1902 }
1903 
1904 #endif /* __SANITIZE_ADDRESS__ */
1905 
1906 /*
1907  * Quotas
1908  */
1909 
1910 void
isc_mempool_setfreemax(isc_mempool_t * mpctx0,unsigned int limit)1911 isc_mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) {
1912 	REQUIRE(VALID_MEMPOOL(mpctx0));
1913 
1914 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1915 
1916 	mpctx->freemax = limit;
1917 }
1918 
1919 unsigned int
isc_mempool_getfreemax(isc_mempool_t * mpctx0)1920 isc_mempool_getfreemax(isc_mempool_t *mpctx0) {
1921 	REQUIRE(VALID_MEMPOOL(mpctx0));
1922 
1923 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1924 
1925 	return (mpctx->freemax);
1926 }
1927 
1928 unsigned int
isc_mempool_getfreecount(isc_mempool_t * mpctx0)1929 isc_mempool_getfreecount(isc_mempool_t *mpctx0) {
1930 	REQUIRE(VALID_MEMPOOL(mpctx0));
1931 
1932 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1933 
1934 	return (mpctx->freecount);
1935 }
1936 
1937 void
isc_mempool_setmaxalloc(isc_mempool_t * mpctx0,unsigned int limit)1938 isc_mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
1939 	REQUIRE(VALID_MEMPOOL(mpctx0));
1940 	REQUIRE(limit > 0);
1941 
1942 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1943 
1944 	mpctx->maxalloc = limit;
1945 }
1946 
1947 unsigned int
isc_mempool_getmaxalloc(isc_mempool_t * mpctx0)1948 isc_mempool_getmaxalloc(isc_mempool_t *mpctx0) {
1949 	REQUIRE(VALID_MEMPOOL(mpctx0));
1950 
1951 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1952 
1953 	return (mpctx->maxalloc);
1954 }
1955 
1956 unsigned int
isc_mempool_getallocated(isc_mempool_t * mpctx0)1957 isc_mempool_getallocated(isc_mempool_t *mpctx0) {
1958 	REQUIRE(VALID_MEMPOOL(mpctx0));
1959 
1960 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1961 
1962 	return (mpctx->allocated);
1963 }
1964 
1965 void
isc_mempool_setfillcount(isc_mempool_t * mpctx0,unsigned int limit)1966 isc_mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
1967 	REQUIRE(VALID_MEMPOOL(mpctx0));
1968 	REQUIRE(limit > 0);
1969 
1970 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1971 
1972 	mpctx->fillcount = limit;
1973 }
1974 
1975 unsigned int
isc_mempool_getfillcount(isc_mempool_t * mpctx0)1976 isc_mempool_getfillcount(isc_mempool_t *mpctx0) {
1977 	REQUIRE(VALID_MEMPOOL(mpctx0));
1978 
1979 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1980 
1981 	return (mpctx->fillcount);
1982 }
1983 
1984 /*
1985  * Requires contextslock to be held by caller.
1986  */
1987 static void
print_contexts(FILE * file)1988 print_contexts(FILE *file) {
1989 	isc__mem_t *ctx;
1990 
1991 	for (ctx = ISC_LIST_HEAD(contexts); ctx != NULL;
1992 	     ctx = ISC_LIST_NEXT(ctx, link))
1993 	{
1994 		fprintf(file, "context: %p (%s): %" PRIuFAST32 " references\n",
1995 			ctx, ctx->name[0] == 0 ? "<unknown>" : ctx->name,
1996 			isc_refcount_current(&ctx->references));
1997 		print_active(ctx, file);
1998 	}
1999 	fflush(file);
2000 }
2001 
2002 static atomic_uintptr_t checkdestroyed = 0;
2003 
2004 void
isc_mem_checkdestroyed(FILE * file)2005 isc_mem_checkdestroyed(FILE *file) {
2006 	atomic_store_release(&checkdestroyed, (uintptr_t)file);
2007 }
2008 
2009 void
isc__mem_checkdestroyed(void)2010 isc__mem_checkdestroyed(void) {
2011 	FILE *file = (FILE *)atomic_load_acquire(&checkdestroyed);
2012 
2013 	if (file == NULL) {
2014 		return;
2015 	}
2016 
2017 	LOCK(&contextslock);
2018 	if (!ISC_LIST_EMPTY(contexts)) {
2019 #if ISC_MEM_TRACKLINES
2020 		if (ISC_UNLIKELY((isc_mem_debugging & TRACE_OR_RECORD) != 0)) {
2021 			print_contexts(file);
2022 		}
2023 #endif /* if ISC_MEM_TRACKLINES */
2024 		UNREACHABLE();
2025 	}
2026 	UNLOCK(&contextslock);
2027 }
2028 
2029 unsigned int
isc_mem_references(isc_mem_t * ctx0)2030 isc_mem_references(isc_mem_t *ctx0) {
2031 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
2032 	return (isc_refcount_current(&ctx->references));
2033 }
2034 
2035 typedef struct summarystat {
2036 	uint64_t total;
2037 	uint64_t inuse;
2038 	uint64_t malloced;
2039 	uint64_t blocksize;
2040 	uint64_t contextsize;
2041 } summarystat_t;
2042 
2043 #ifdef HAVE_LIBXML2
2044 #define TRY0(a)                     \
2045 	do {                        \
2046 		xmlrc = (a);        \
2047 		if (xmlrc < 0)      \
2048 			goto error; \
2049 	} while (0)
2050 static int
xml_renderctx(isc__mem_t * ctx,summarystat_t * summary,xmlTextWriterPtr writer)2051 xml_renderctx(isc__mem_t *ctx, summarystat_t *summary,
2052 	      xmlTextWriterPtr writer) {
2053 	REQUIRE(VALID_CONTEXT(ctx));
2054 
2055 	int xmlrc;
2056 
2057 	MCTXLOCK(ctx);
2058 
2059 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"));
2060 
2061 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
2062 	TRY0(xmlTextWriterWriteFormatString(writer, "%p", ctx));
2063 	TRY0(xmlTextWriterEndElement(writer)); /* id */
2064 
2065 	if (ctx->name[0] != 0) {
2066 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
2067 		TRY0(xmlTextWriterWriteFormatString(writer, "%s", ctx->name));
2068 		TRY0(xmlTextWriterEndElement(writer)); /* name */
2069 	}
2070 
2071 	summary->contextsize += sizeof(*ctx) +
2072 				(ctx->max_size + 1) * sizeof(struct stats) +
2073 				ctx->max_size * sizeof(element *) +
2074 				ctx->basic_table_count * sizeof(char *);
2075 #if ISC_MEM_TRACKLINES
2076 	if (ctx->debuglist != NULL) {
2077 		summary->contextsize += DEBUG_TABLE_COUNT *
2078 						sizeof(debuglist_t) +
2079 					ctx->debuglistcnt * sizeof(debuglink_t);
2080 	}
2081 #endif /* if ISC_MEM_TRACKLINES */
2082 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
2083 	TRY0(xmlTextWriterWriteFormatString(
2084 		writer, "%" PRIuFAST32,
2085 		isc_refcount_current(&ctx->references)));
2086 	TRY0(xmlTextWriterEndElement(writer)); /* references */
2087 
2088 	summary->total += ctx->total;
2089 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"));
2090 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2091 					    (uint64_t)ctx->total));
2092 	TRY0(xmlTextWriterEndElement(writer)); /* total */
2093 
2094 	summary->inuse += ctx->inuse;
2095 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"));
2096 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2097 					    (uint64_t)ctx->inuse));
2098 	TRY0(xmlTextWriterEndElement(writer)); /* inuse */
2099 
2100 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"));
2101 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2102 					    (uint64_t)ctx->maxinuse));
2103 	TRY0(xmlTextWriterEndElement(writer)); /* maxinuse */
2104 
2105 	summary->malloced += ctx->malloced;
2106 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "malloced"));
2107 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2108 					    (uint64_t)ctx->malloced));
2109 	TRY0(xmlTextWriterEndElement(writer)); /* malloced */
2110 
2111 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxmalloced"));
2112 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2113 					    (uint64_t)ctx->maxmalloced));
2114 	TRY0(xmlTextWriterEndElement(writer)); /* maxmalloced */
2115 
2116 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"));
2117 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2118 		summary->blocksize += ctx->basic_table_count *
2119 				      NUM_BASIC_BLOCKS * ctx->mem_target;
2120 		TRY0(xmlTextWriterWriteFormatString(
2121 			writer, "%" PRIu64 "",
2122 			(uint64_t)ctx->basic_table_count * NUM_BASIC_BLOCKS *
2123 				ctx->mem_target));
2124 	} else {
2125 		TRY0(xmlTextWriterWriteFormatString(writer, "%s", "-"));
2126 	}
2127 	TRY0(xmlTextWriterEndElement(writer)); /* blocksize */
2128 
2129 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"));
2130 	TRY0(xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt));
2131 	TRY0(xmlTextWriterEndElement(writer)); /* pools */
2132 	summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2133 
2134 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"));
2135 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2136 					    (uint64_t)ctx->hi_water));
2137 	TRY0(xmlTextWriterEndElement(writer)); /* hiwater */
2138 
2139 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"));
2140 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2141 					    (uint64_t)ctx->lo_water));
2142 	TRY0(xmlTextWriterEndElement(writer)); /* lowater */
2143 
2144 	TRY0(xmlTextWriterEndElement(writer)); /* context */
2145 
2146 error:
2147 	MCTXUNLOCK(ctx);
2148 
2149 	return (xmlrc);
2150 }
2151 
2152 int
isc_mem_renderxml(void * writer0)2153 isc_mem_renderxml(void *writer0) {
2154 	isc__mem_t *ctx;
2155 	summarystat_t summary;
2156 	uint64_t lost;
2157 	int xmlrc;
2158 	xmlTextWriterPtr writer = (xmlTextWriterPtr)writer0;
2159 
2160 	memset(&summary, 0, sizeof(summary));
2161 
2162 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"));
2163 
2164 	LOCK(&contextslock);
2165 	lost = totallost;
2166 	for (ctx = ISC_LIST_HEAD(contexts); ctx != NULL;
2167 	     ctx = ISC_LIST_NEXT(ctx, link))
2168 	{
2169 		xmlrc = xml_renderctx(ctx, &summary, writer);
2170 		if (xmlrc < 0) {
2171 			UNLOCK(&contextslock);
2172 			goto error;
2173 		}
2174 	}
2175 	UNLOCK(&contextslock);
2176 
2177 	TRY0(xmlTextWriterEndElement(writer)); /* contexts */
2178 
2179 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"));
2180 
2181 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"));
2182 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2183 					    summary.total));
2184 	TRY0(xmlTextWriterEndElement(writer)); /* TotalUse */
2185 
2186 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"));
2187 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2188 					    summary.inuse));
2189 	TRY0(xmlTextWriterEndElement(writer)); /* InUse */
2190 
2191 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "Malloced"));
2192 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2193 					    summary.malloced));
2194 	TRY0(xmlTextWriterEndElement(writer)); /* InUse */
2195 
2196 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"));
2197 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2198 					    summary.blocksize));
2199 	TRY0(xmlTextWriterEndElement(writer)); /* BlockSize */
2200 
2201 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"));
2202 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
2203 					    summary.contextsize));
2204 	TRY0(xmlTextWriterEndElement(writer)); /* ContextSize */
2205 
2206 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"));
2207 	TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "", lost));
2208 	TRY0(xmlTextWriterEndElement(writer)); /* Lost */
2209 
2210 	TRY0(xmlTextWriterEndElement(writer)); /* summary */
2211 error:
2212 	return (xmlrc);
2213 }
2214 
2215 #endif /* HAVE_LIBXML2 */
2216 
2217 #ifdef HAVE_JSON_C
2218 #define CHECKMEM(m) RUNTIME_CHECK(m != NULL)
2219 
2220 static isc_result_t
json_renderctx(isc__mem_t * ctx,summarystat_t * summary,json_object * array)2221 json_renderctx(isc__mem_t *ctx, summarystat_t *summary, json_object *array) {
2222 	REQUIRE(VALID_CONTEXT(ctx));
2223 	REQUIRE(summary != NULL);
2224 	REQUIRE(array != NULL);
2225 
2226 	json_object *ctxobj, *obj;
2227 	char buf[1024];
2228 
2229 	MCTXLOCK(ctx);
2230 
2231 	summary->contextsize += sizeof(*ctx) +
2232 				(ctx->max_size + 1) * sizeof(struct stats) +
2233 				ctx->max_size * sizeof(element *) +
2234 				ctx->basic_table_count * sizeof(char *);
2235 	summary->total += ctx->total;
2236 	summary->inuse += ctx->inuse;
2237 	summary->malloced += ctx->malloced;
2238 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2239 		summary->blocksize += ctx->basic_table_count *
2240 				      NUM_BASIC_BLOCKS * ctx->mem_target;
2241 	}
2242 #if ISC_MEM_TRACKLINES
2243 	if (ctx->debuglist != NULL) {
2244 		summary->contextsize += DEBUG_TABLE_COUNT *
2245 						sizeof(debuglist_t) +
2246 					ctx->debuglistcnt * sizeof(debuglink_t);
2247 	}
2248 #endif /* if ISC_MEM_TRACKLINES */
2249 
2250 	ctxobj = json_object_new_object();
2251 	CHECKMEM(ctxobj);
2252 
2253 	snprintf(buf, sizeof(buf), "%p", ctx);
2254 	obj = json_object_new_string(buf);
2255 	CHECKMEM(obj);
2256 	json_object_object_add(ctxobj, "id", obj);
2257 
2258 	if (ctx->name[0] != 0) {
2259 		obj = json_object_new_string(ctx->name);
2260 		CHECKMEM(obj);
2261 		json_object_object_add(ctxobj, "name", obj);
2262 	}
2263 
2264 	obj = json_object_new_int64(isc_refcount_current(&ctx->references));
2265 	CHECKMEM(obj);
2266 	json_object_object_add(ctxobj, "references", obj);
2267 
2268 	obj = json_object_new_int64(ctx->total);
2269 	CHECKMEM(obj);
2270 	json_object_object_add(ctxobj, "total", obj);
2271 
2272 	obj = json_object_new_int64(ctx->inuse);
2273 	CHECKMEM(obj);
2274 	json_object_object_add(ctxobj, "inuse", obj);
2275 
2276 	obj = json_object_new_int64(ctx->maxinuse);
2277 	CHECKMEM(obj);
2278 	json_object_object_add(ctxobj, "maxinuse", obj);
2279 
2280 	obj = json_object_new_int64(ctx->malloced);
2281 	CHECKMEM(obj);
2282 	json_object_object_add(ctxobj, "malloced", obj);
2283 
2284 	obj = json_object_new_int64(ctx->maxmalloced);
2285 	CHECKMEM(obj);
2286 	json_object_object_add(ctxobj, "maxmalloced", obj);
2287 
2288 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2289 		uint64_t blocksize;
2290 		blocksize = ctx->basic_table_count * NUM_BASIC_BLOCKS *
2291 			    ctx->mem_target;
2292 		obj = json_object_new_int64(blocksize);
2293 		CHECKMEM(obj);
2294 		json_object_object_add(ctxobj, "blocksize", obj);
2295 	}
2296 
2297 	obj = json_object_new_int64(ctx->poolcnt);
2298 	CHECKMEM(obj);
2299 	json_object_object_add(ctxobj, "pools", obj);
2300 
2301 	summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2302 
2303 	obj = json_object_new_int64(ctx->hi_water);
2304 	CHECKMEM(obj);
2305 	json_object_object_add(ctxobj, "hiwater", obj);
2306 
2307 	obj = json_object_new_int64(ctx->lo_water);
2308 	CHECKMEM(obj);
2309 	json_object_object_add(ctxobj, "lowater", obj);
2310 
2311 	MCTXUNLOCK(ctx);
2312 	json_object_array_add(array, ctxobj);
2313 	return (ISC_R_SUCCESS);
2314 }
2315 
2316 isc_result_t
isc_mem_renderjson(void * memobj0)2317 isc_mem_renderjson(void *memobj0) {
2318 	isc_result_t result = ISC_R_SUCCESS;
2319 	isc__mem_t *ctx;
2320 	summarystat_t summary;
2321 	uint64_t lost;
2322 	json_object *ctxarray, *obj;
2323 	json_object *memobj = (json_object *)memobj0;
2324 
2325 	memset(&summary, 0, sizeof(summary));
2326 
2327 	ctxarray = json_object_new_array();
2328 	CHECKMEM(ctxarray);
2329 
2330 	LOCK(&contextslock);
2331 	lost = totallost;
2332 	for (ctx = ISC_LIST_HEAD(contexts); ctx != NULL;
2333 	     ctx = ISC_LIST_NEXT(ctx, link))
2334 	{
2335 		result = json_renderctx(ctx, &summary, ctxarray);
2336 		if (result != ISC_R_SUCCESS) {
2337 			UNLOCK(&contextslock);
2338 			goto error;
2339 		}
2340 	}
2341 	UNLOCK(&contextslock);
2342 
2343 	obj = json_object_new_int64(summary.total);
2344 	CHECKMEM(obj);
2345 	json_object_object_add(memobj, "TotalUse", obj);
2346 
2347 	obj = json_object_new_int64(summary.inuse);
2348 	CHECKMEM(obj);
2349 	json_object_object_add(memobj, "InUse", obj);
2350 
2351 	obj = json_object_new_int64(summary.malloced);
2352 	CHECKMEM(obj);
2353 	json_object_object_add(memobj, "Malloced", obj);
2354 
2355 	obj = json_object_new_int64(summary.blocksize);
2356 	CHECKMEM(obj);
2357 	json_object_object_add(memobj, "BlockSize", obj);
2358 
2359 	obj = json_object_new_int64(summary.contextsize);
2360 	CHECKMEM(obj);
2361 	json_object_object_add(memobj, "ContextSize", obj);
2362 
2363 	obj = json_object_new_int64(lost);
2364 	CHECKMEM(obj);
2365 	json_object_object_add(memobj, "Lost", obj);
2366 
2367 	json_object_object_add(memobj, "contexts", ctxarray);
2368 	return (ISC_R_SUCCESS);
2369 
2370 error:
2371 	if (ctxarray != NULL) {
2372 		json_object_put(ctxarray);
2373 	}
2374 	return (result);
2375 }
2376 #endif /* HAVE_JSON_C */
2377 
2378 void
isc_mem_create(isc_mem_t ** mctxp)2379 isc_mem_create(isc_mem_t **mctxp) {
2380 	mem_create(mctxp, isc_mem_defaultflags);
2381 }
2382 
2383 void *
isc__mem_get(isc_mem_t * mctx,size_t size FLARG)2384 isc__mem_get(isc_mem_t *mctx, size_t size FLARG) {
2385 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2386 
2387 	return (mctx->methods->memget(mctx, size FLARG_PASS));
2388 }
2389 
2390 void
isc__mem_put(isc_mem_t * mctx,void * ptr,size_t size FLARG)2391 isc__mem_put(isc_mem_t *mctx, void *ptr, size_t size FLARG) {
2392 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2393 
2394 	mctx->methods->memput(mctx, ptr, size FLARG_PASS);
2395 }
2396 
2397 void
isc__mem_putanddetach(isc_mem_t ** mctxp,void * ptr,size_t size FLARG)2398 isc__mem_putanddetach(isc_mem_t **mctxp, void *ptr, size_t size FLARG) {
2399 	REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
2400 
2401 	(*mctxp)->methods->memputanddetach(mctxp, ptr, size FLARG_PASS);
2402 }
2403 
2404 void *
isc__mem_allocate(isc_mem_t * mctx,size_t size FLARG)2405 isc__mem_allocate(isc_mem_t *mctx, size_t size FLARG) {
2406 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2407 
2408 	return (mctx->methods->memallocate(mctx, size FLARG_PASS));
2409 }
2410 
2411 void *
isc__mem_reallocate(isc_mem_t * mctx,void * ptr,size_t size FLARG)2412 isc__mem_reallocate(isc_mem_t *mctx, void *ptr, size_t size FLARG) {
2413 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2414 
2415 	return (mctx->methods->memreallocate(mctx, ptr, size FLARG_PASS));
2416 }
2417 
2418 char *
isc__mem_strdup(isc_mem_t * mctx,const char * s FLARG)2419 isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
2420 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2421 
2422 	return (mctx->methods->memstrdup(mctx, s FLARG_PASS));
2423 }
2424 
2425 char *
isc__mem_strndup(isc_mem_t * mctx,const char * s,size_t size FLARG)2426 isc__mem_strndup(isc_mem_t *mctx, const char *s, size_t size FLARG) {
2427 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2428 
2429 	return (mctx->methods->memstrndup(mctx, s, size FLARG_PASS));
2430 }
2431 
2432 void
isc__mem_free(isc_mem_t * mctx,void * ptr FLARG)2433 isc__mem_free(isc_mem_t *mctx, void *ptr FLARG) {
2434 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2435 
2436 	mctx->methods->memfree(mctx, ptr FLARG_PASS);
2437 }
2438 
2439 void
isc__mem_printactive(isc_mem_t * ctx0,FILE * file)2440 isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
2441 #if ISC_MEM_TRACKLINES
2442 	REQUIRE(VALID_CONTEXT(ctx0));
2443 	REQUIRE(file != NULL);
2444 
2445 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
2446 
2447 	print_active(ctx, file);
2448 #else  /* if ISC_MEM_TRACKLINES */
2449 	UNUSED(ctx0);
2450 	UNUSED(file);
2451 #endif /* if ISC_MEM_TRACKLINES */
2452 }
2453