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