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