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