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