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