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