xref: /minix/external/bsd/bind/dist/lib/isc/mem.c (revision 00b67f09)
1 /*	$NetBSD: mem.c,v 1.12 2015/07/08 17:28:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2010, 2012-2015  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1997-2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id */
21 
22 /*! \file */
23 
24 #include <config.h>
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stddef.h>
29 
30 #include <limits.h>
31 
32 #include <isc/bind9.h>
33 #include <isc/json.h>
34 #include <isc/magic.h>
35 #include <isc/mem.h>
36 #include <isc/msgs.h>
37 #include <isc/once.h>
38 #include <isc/ondestroy.h>
39 #include <isc/string.h>
40 #include <isc/mutex.h>
41 #include <isc/print.h>
42 #include <isc/util.h>
43 #include <isc/xml.h>
44 
45 #define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l)
46 #define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l)
47 
48 #ifndef ISC_MEM_DEBUGGING
49 #define ISC_MEM_DEBUGGING 0
50 #endif
51 LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
52 
53 /*
54  * Constants.
55  */
56 
57 #define DEF_MAX_SIZE		1100
58 #define DEF_MEM_TARGET		4096
59 #define ALIGNMENT_SIZE		8U		/*%< must be a power of 2 */
60 #define NUM_BASIC_BLOCKS	64		/*%< must be > 1 */
61 #define TABLE_INCREMENT		1024
62 #define DEBUGLIST_COUNT		1024
63 
64 /*
65  * Types.
66  */
67 typedef struct isc__mem isc__mem_t;
68 typedef struct isc__mempool isc__mempool_t;
69 
70 #if ISC_MEM_TRACKLINES
71 typedef struct debuglink debuglink_t;
72 struct debuglink {
73 	ISC_LINK(debuglink_t)	link;
74 	const void	       *ptr[DEBUGLIST_COUNT];
75 	size_t			size[DEBUGLIST_COUNT];
76 	const char	       *file[DEBUGLIST_COUNT];
77 	unsigned int		line[DEBUGLIST_COUNT];
78 	unsigned int		count;
79 };
80 
81 #define FLARG_PASS	, file, line
82 #define FLARG		, const char *file, unsigned int line
83 #else
84 #define FLARG_PASS
85 #define FLARG
86 #endif
87 
88 typedef struct element element;
89 struct element {
90 	element *		next;
91 };
92 
93 typedef struct {
94 	/*!
95 	 * This structure must be ALIGNMENT_SIZE bytes.
96 	 */
97 	union {
98 		size_t		size;
99 		isc__mem_t	*ctx;
100 		char		bytes[ALIGNMENT_SIZE];
101 	} u;
102 } size_info;
103 
104 struct stats {
105 	unsigned long		gets;
106 	unsigned long		totalgets;
107 	unsigned long		blocks;
108 	unsigned long		freefrags;
109 };
110 
111 #define MEM_MAGIC		ISC_MAGIC('M', 'e', 'm', 'C')
112 #define VALID_CONTEXT(c)	ISC_MAGIC_VALID(c, MEM_MAGIC)
113 
114 #if ISC_MEM_TRACKLINES
115 typedef ISC_LIST(debuglink_t)	debuglist_t;
116 #endif
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 static isc_mutex_t 		createlock;
125 
126 /*%
127  * Total size of lost memory due to a bug of external library.
128  * Locked by the global lock.
129  */
130 static isc_uint64_t		totallost;
131 
132 struct isc__mem {
133 	isc_mem_t		common;
134 	isc_ondestroy_t		ondestroy;
135 	unsigned int		flags;
136 	isc_mutex_t		lock;
137 	isc_memalloc_t		memalloc;
138 	isc_memfree_t		memfree;
139 	void *			arg;
140 	size_t			max_size;
141 	isc_boolean_t		checkfree;
142 	struct stats *		stats;
143 	unsigned int		references;
144 	char			name[16];
145 	void *			tag;
146 	size_t			quota;
147 	size_t			total;
148 	size_t			inuse;
149 	size_t			maxinuse;
150 	size_t			hi_water;
151 	size_t			lo_water;
152 	isc_boolean_t		hi_called;
153 	isc_boolean_t		is_overmem;
154 	isc_mem_water_t		water;
155 	void *			water_arg;
156 	ISC_LIST(isc__mempool_t) pools;
157 	unsigned int		poolcnt;
158 
159 	/*  ISC_MEMFLAG_INTERNAL */
160 	size_t			mem_target;
161 	element **		freelists;
162 	element *		basic_blocks;
163 	unsigned char **	basic_table;
164 	unsigned int		basic_table_count;
165 	unsigned int		basic_table_size;
166 	unsigned char *		lowest;
167 	unsigned char *		highest;
168 
169 #if ISC_MEM_TRACKLINES
170 	debuglist_t *	 	debuglist;
171 	unsigned int		debuglistcnt;
172 #endif
173 
174 	unsigned int		memalloc_failures;
175 	ISC_LINK(isc__mem_t)	link;
176 };
177 
178 #define MEMPOOL_MAGIC		ISC_MAGIC('M', 'E', 'M', 'p')
179 #define VALID_MEMPOOL(c)	ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
180 
181 struct isc__mempool {
182 	/* always unlocked */
183 	isc_mempool_t	common;		/*%< common header of mempool's */
184 	isc_mutex_t    *lock;		/*%< optional lock */
185 	isc__mem_t      *mctx;		/*%< our memory context */
186 	/*%< locked via the memory context's lock */
187 	ISC_LINK(isc__mempool_t)	link;	/*%< next pool in this mem context */
188 	/*%< optionally locked from here down */
189 	element	       *items;		/*%< low water item list */
190 	size_t		size;		/*%< size of each item on this pool */
191 	unsigned int	maxalloc;	/*%< max number of items allowed */
192 	unsigned int	allocated;	/*%< # of items currently given out */
193 	unsigned int	freecount;	/*%< # of items on reserved list */
194 	unsigned int	freemax;	/*%< # of items allowed on free list */
195 	unsigned int	fillcount;	/*%< # of items to fetch on each fill */
196 	/*%< Stats only. */
197 	unsigned int	gets;		/*%< # of requests to this pool */
198 	/*%< Debugging only. */
199 #if ISC_MEMPOOL_NAMES
200 	char		name[16];	/*%< printed name in stats reports */
201 #endif
202 };
203 
204 /*
205  * Private Inline-able.
206  */
207 
208 #if ! ISC_MEM_TRACKLINES
209 #define ADD_TRACE(a, b, c, d, e)
210 #define DELETE_TRACE(a, b, c, d, e)
211 #define ISC_MEMFUNC_SCOPE
212 #else
213 #define ADD_TRACE(a, b, c, d, e) \
214 	do { \
215 		if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
216 					  ISC_MEM_DEBUGRECORD)) != 0 && \
217 		     b != NULL) \
218 			 add_trace_entry(a, b, c, d, e); \
219 	} while (/*CONSTCOND*/0)
220 #define DELETE_TRACE(a, b, c, d, e)	delete_trace_entry(a, b, c, d, e)
221 
222 static void
223 print_active(isc__mem_t *ctx, FILE *out);
224 
225 /*%
226  * The following are intended for internal use (indicated by "isc__"
227  * prefix) but are not declared as static, allowing direct access
228  * from unit tests, etc.
229  */
230 
231 isc_result_t
232 isc__mem_create2(size_t init_max_size, size_t target_size,
233 		 isc_mem_t **ctxp, unsigned int flags);
234 void
235 isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp);
236 void
237 isc__mem_detach(isc_mem_t **ctxp);
238 void
239 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG);
240 void
241 isc__mem_destroy(isc_mem_t **ctxp);
242 isc_result_t
243 isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event);
244 void *
245 isc___mem_get(isc_mem_t *ctx, size_t size FLARG);
246 void
247 isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG);
248 void
249 isc__mem_stats(isc_mem_t *ctx, FILE *out);
250 void *
251 isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG);
252 void *
253 isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG);
254 void
255 isc___mem_free(isc_mem_t *ctx, void *ptr FLARG);
256 char *
257 isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG);
258 void
259 isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag);
260 void
261 isc__mem_setquota(isc_mem_t *ctx, size_t quota);
262 size_t
263 isc__mem_getquota(isc_mem_t *ctx);
264 size_t
265 isc__mem_inuse(isc_mem_t *ctx);
266 size_t
267 isc__mem_maxinuse(isc_mem_t *ctx);
268 size_t
269 isc__mem_total(isc_mem_t *ctx);
270 isc_boolean_t
271 isc__mem_isovermem(isc_mem_t *ctx);
272 void
273 isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
274 		  size_t hiwater, size_t lowater);
275 void
276 isc__mem_waterack(isc_mem_t *ctx0, int flag);
277 void
278 isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag);
279 const char *
280 isc__mem_getname(isc_mem_t *ctx);
281 void *
282 isc__mem_gettag(isc_mem_t *ctx);
283 isc_result_t
284 isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
285 void
286 isc__mempool_setname(isc_mempool_t *mpctx, const char *name);
287 void
288 isc__mempool_destroy(isc_mempool_t **mpctxp);
289 void
290 isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock);
291 void *
292 isc___mempool_get(isc_mempool_t *mpctx FLARG);
293 void
294 isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG);
295 void
296 isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit);
297 unsigned int
298 isc__mempool_getfreemax(isc_mempool_t *mpctx);
299 unsigned int
300 isc__mempool_getfreecount(isc_mempool_t *mpctx);
301 void
302 isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit);
303 unsigned int
304 isc__mempool_getmaxalloc(isc_mempool_t *mpctx);
305 unsigned int
306 isc__mempool_getallocated(isc_mempool_t *mpctx);
307 void
308 isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
309 unsigned int
310 isc__mempool_getfillcount(isc_mempool_t *mpctx);
311 void
312 isc__mem_printactive(isc_mem_t *ctx0, FILE *file);
313 void
314 isc__mem_printallactive(FILE *file);
315 unsigned int
316 isc__mem_references(isc_mem_t *ctx0);
317 #endif /* ISC_MEM_TRACKLINES */
318 
319 static struct isc__memmethods {
320 	isc_memmethods_t methods;
321 
322 	/*%
323 	 * The following are defined just for avoiding unused static functions.
324 	 */
325 	void *createx, *create, *create2, *ondestroy, *stats,
326 	     *setquota, *getquota, *setname, *getname, *gettag;
327 } memmethods = {
328 	{
329 		isc__mem_attach,
330 		isc__mem_detach,
331 		isc__mem_destroy,
332 		isc___mem_get,
333 		isc___mem_put,
334 		isc___mem_putanddetach,
335 		isc___mem_allocate,
336 		isc___mem_reallocate,
337 		isc___mem_strdup,
338 		isc___mem_free,
339 		isc__mem_setdestroycheck,
340 		isc__mem_setwater,
341 		isc__mem_waterack,
342 		isc__mem_inuse,
343 		isc__mem_maxinuse,
344 		isc__mem_total,
345 		isc__mem_isovermem,
346 		isc__mempool_create
347 	},
348 	(void *)isc_mem_createx,
349 	(void *)isc_mem_create,
350 	(void *)isc_mem_create2,
351 	(void *)isc_mem_ondestroy,
352 	(void *)isc_mem_stats,
353 	(void *)isc_mem_setquota,
354 	(void *)isc_mem_getquota,
355 	(void *)isc_mem_setname,
356 	(void *)isc_mem_getname,
357 	(void *)isc_mem_gettag
358 };
359 
360 static struct isc__mempoolmethods {
361 	isc_mempoolmethods_t methods;
362 
363 	/*%
364 	 * The following are defined just for avoiding unused static functions.
365 	 */
366 	void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount;
367 } mempoolmethods = {
368 	{
369 		isc__mempool_destroy,
370 		isc___mempool_get,
371 		isc___mempool_put,
372 		isc__mempool_getallocated,
373 		isc__mempool_setmaxalloc,
374 		isc__mempool_setfreemax,
375 		isc__mempool_setname,
376 		isc__mempool_associatelock,
377 		isc__mempool_setfillcount
378 	},
379 	(void *)isc_mempool_getfreemax,
380 	(void *)isc_mempool_getfreecount,
381 	(void *)isc_mempool_getmaxalloc,
382 	(void *)isc_mempool_getfillcount
383 };
384 
385 #if ISC_MEM_TRACKLINES
386 /*!
387  * mctx must be locked.
388  */
389 static inline void
add_trace_entry(isc__mem_t * mctx,const void * ptr,size_t size FLARG)390 add_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size FLARG) {
391 	debuglink_t *dl;
392 	unsigned int i;
393 	size_t mysize = size;
394 
395 	if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
396 		fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
397 					       ISC_MSG_ADDTRACE,
398 					       "add %p size %u "
399 					       "file %s line %u mctx %p\n"),
400 			ptr, size, file, line, mctx);
401 
402 	if (mctx->debuglist == NULL)
403 		return;
404 
405 	if (mysize > mctx->max_size)
406 		mysize = mctx->max_size;
407 
408 	dl = ISC_LIST_HEAD(mctx->debuglist[mysize]);
409 	while (dl != NULL) {
410 		if (dl->count == DEBUGLIST_COUNT)
411 			goto next;
412 		for (i = 0; i < DEBUGLIST_COUNT; i++) {
413 			if (dl->ptr[i] == NULL) {
414 				dl->ptr[i] = ptr;
415 				dl->size[i] = size;
416 				dl->file[i] = file;
417 				dl->line[i] = line;
418 				dl->count++;
419 				return;
420 			}
421 		}
422 	next:
423 		dl = ISC_LIST_NEXT(dl, link);
424 	}
425 
426 	dl = malloc(sizeof(debuglink_t));
427 	INSIST(dl != NULL);
428 
429 	ISC_LINK_INIT(dl, link);
430 	for (i = 1; i < DEBUGLIST_COUNT; i++) {
431 		dl->ptr[i] = NULL;
432 		dl->size[i] = 0;
433 		dl->file[i] = NULL;
434 		dl->line[i] = 0;
435 	}
436 
437 	dl->ptr[0] = ptr;
438 	dl->size[0] = size;
439 	dl->file[0] = file;
440 	dl->line[0] = line;
441 	dl->count = 1;
442 
443 	ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link);
444 	mctx->debuglistcnt++;
445 }
446 
447 static inline void
delete_trace_entry(isc__mem_t * mctx,const void * ptr,size_t size,const char * file,unsigned int line)448 delete_trace_entry(isc__mem_t *mctx, const void *ptr, size_t size,
449 		   const char *file, unsigned int line)
450 {
451 	debuglink_t *dl;
452 	unsigned int i;
453 
454 	if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0)
455 		fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
456 					       ISC_MSG_DELTRACE,
457 					       "del %p size %u "
458 					       "file %s line %u mctx %p\n"),
459 			ptr, size, file, line, mctx);
460 
461 	if (mctx->debuglist == NULL)
462 		return;
463 
464 	if (size > mctx->max_size)
465 		size = mctx->max_size;
466 
467 	dl = ISC_LIST_HEAD(mctx->debuglist[size]);
468 	while (dl != NULL) {
469 		for (i = 0; i < DEBUGLIST_COUNT; i++) {
470 			if (dl->ptr[i] == ptr) {
471 				dl->ptr[i] = NULL;
472 				dl->size[i] = 0;
473 				dl->file[i] = NULL;
474 				dl->line[i] = 0;
475 
476 				INSIST(dl->count > 0);
477 				dl->count--;
478 				if (dl->count == 0) {
479 					ISC_LIST_UNLINK(mctx->debuglist[size],
480 							dl, link);
481 					free(dl);
482 				}
483 				return;
484 			}
485 		}
486 		dl = ISC_LIST_NEXT(dl, link);
487 	}
488 
489 	/*
490 	 * If we get here, we didn't find the item on the list.  We're
491 	 * screwed.
492 	 */
493 	INSIST(dl != NULL);
494 }
495 #endif /* ISC_MEM_TRACKLINES */
496 
497 static inline size_t
rmsize(size_t size)498 rmsize(size_t size) {
499 	/*
500 	 * round down to ALIGNMENT_SIZE
501 	 */
502 	return (size & (~(ALIGNMENT_SIZE - 1)));
503 }
504 
505 static inline size_t
quantize(size_t size)506 quantize(size_t size) {
507 	/*!
508 	 * Round up the result in order to get a size big
509 	 * enough to satisfy the request and be aligned on ALIGNMENT_SIZE
510 	 * byte boundaries.
511 	 */
512 
513 	if (size == 0U)
514 		return (ALIGNMENT_SIZE);
515 	return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
516 }
517 
518 static inline isc_boolean_t
more_basic_blocks(isc__mem_t * ctx)519 more_basic_blocks(isc__mem_t *ctx) {
520 	void *new;
521 	unsigned char *curr, *next;
522 	unsigned char *first, *last;
523 	unsigned char **table;
524 	unsigned int table_size;
525 	size_t increment;
526 	int i;
527 
528 	/* Require: we hold the context lock. */
529 
530 	/*
531 	 * Did we hit the quota for this context?
532 	 */
533 	increment = NUM_BASIC_BLOCKS * ctx->mem_target;
534 	if (ctx->quota != 0U && ctx->total + increment > ctx->quota)
535 		return (ISC_FALSE);
536 
537 	INSIST(ctx->basic_table_count <= ctx->basic_table_size);
538 	if (ctx->basic_table_count == ctx->basic_table_size) {
539 		table_size = ctx->basic_table_size + TABLE_INCREMENT;
540 		table = (ctx->memalloc)(ctx->arg,
541 					table_size * sizeof(unsigned char *));
542 		if (table == NULL) {
543 			ctx->memalloc_failures++;
544 			return (ISC_FALSE);
545 		}
546 		if (ctx->basic_table_size != 0) {
547 			memmove(table, ctx->basic_table,
548 				ctx->basic_table_size *
549 				  sizeof(unsigned char *));
550 			(ctx->memfree)(ctx->arg, ctx->basic_table);
551 		}
552 		ctx->basic_table = table;
553 		ctx->basic_table_size = table_size;
554 	}
555 
556 	new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target);
557 	if (new == NULL) {
558 		ctx->memalloc_failures++;
559 		return (ISC_FALSE);
560 	}
561 	ctx->total += increment;
562 	ctx->basic_table[ctx->basic_table_count] = new;
563 	ctx->basic_table_count++;
564 
565 	curr = new;
566 	next = curr + ctx->mem_target;
567 	for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
568 		((element *)curr)->next = (element *)next;
569 		curr = next;
570 		next += ctx->mem_target;
571 	}
572 	/*
573 	 * curr is now pointing at the last block in the
574 	 * array.
575 	 */
576 	((element *)curr)->next = NULL;
577 	first = new;
578 	last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1;
579 	if (first < ctx->lowest || ctx->lowest == NULL)
580 		ctx->lowest = first;
581 	if (last > ctx->highest)
582 		ctx->highest = last;
583 	ctx->basic_blocks = new;
584 
585 	return (ISC_TRUE);
586 }
587 
588 static inline isc_boolean_t
more_frags(isc__mem_t * ctx,size_t new_size)589 more_frags(isc__mem_t *ctx, size_t new_size) {
590 	int i, frags;
591 	size_t total_size;
592 	void *new;
593 	unsigned char *curr, *next;
594 
595 	/*!
596 	 * Try to get more fragments by chopping up a basic block.
597 	 */
598 
599 	if (ctx->basic_blocks == NULL) {
600 		if (!more_basic_blocks(ctx)) {
601 			/*
602 			 * We can't get more memory from the OS, or we've
603 			 * hit the quota for this context.
604 			 */
605 			/*
606 			 * XXXRTH  "At quota" notification here.
607 			 */
608 			return (ISC_FALSE);
609 		}
610 	}
611 
612 	total_size = ctx->mem_target;
613 	new = ctx->basic_blocks;
614 	ctx->basic_blocks = ctx->basic_blocks->next;
615 	frags = (int)(total_size / new_size);
616 	ctx->stats[new_size].blocks++;
617 	ctx->stats[new_size].freefrags += frags;
618 	/*
619 	 * Set up a linked-list of blocks of size
620 	 * "new_size".
621 	 */
622 	curr = new;
623 	next = curr + new_size;
624 	total_size -= new_size;
625 	for (i = 0; i < (frags - 1); i++) {
626 		((element *)curr)->next = (element *)next;
627 		curr = next;
628 		next += new_size;
629 		total_size -= new_size;
630 	}
631 	/*
632 	 * Add the remaining fragment of the basic block to a free list.
633 	 */
634 	total_size = rmsize(total_size);
635 	if (total_size > 0U) {
636 		((element *)next)->next = ctx->freelists[total_size];
637 		ctx->freelists[total_size] = (element *)next;
638 		ctx->stats[total_size].freefrags++;
639 	}
640 	/*
641 	 * curr is now pointing at the last block in the
642 	 * array.
643 	 */
644 	((element *)curr)->next = NULL;
645 	ctx->freelists[new_size] = new;
646 
647 	return (ISC_TRUE);
648 }
649 
650 static inline void *
mem_getunlocked(isc__mem_t * ctx,size_t size)651 mem_getunlocked(isc__mem_t *ctx, size_t size) {
652 	size_t new_size = quantize(size);
653 	void *ret;
654 
655 	if (size >= ctx->max_size || new_size >= ctx->max_size) {
656 		/*
657 		 * memget() was called on something beyond our upper limit.
658 		 */
659 		if (ctx->quota != 0U && ctx->total + size > ctx->quota) {
660 			ret = NULL;
661 			goto done;
662 		}
663 		ret = (ctx->memalloc)(ctx->arg, size);
664 		if (ret == NULL) {
665 			ctx->memalloc_failures++;
666 			goto done;
667 		}
668 		ctx->total += size;
669 		ctx->inuse += size;
670 		ctx->stats[ctx->max_size].gets++;
671 		ctx->stats[ctx->max_size].totalgets++;
672 		/*
673 		 * If we don't set new_size to size, then the
674 		 * ISC_MEM_FILL code might write over bytes we
675 		 * don't own.
676 		 */
677 		new_size = size;
678 		goto done;
679 	}
680 
681 	/*
682 	 * If there are no blocks in the free list for this size, get a chunk
683 	 * of memory and then break it up into "new_size"-sized blocks, adding
684 	 * them to the free list.
685 	 */
686 	if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size))
687 		return (NULL);
688 
689 	/*
690 	 * The free list uses the "rounded-up" size "new_size".
691 	 */
692 	ret = ctx->freelists[new_size];
693 	ctx->freelists[new_size] = ctx->freelists[new_size]->next;
694 
695 	/*
696 	 * The stats[] uses the _actual_ "size" requested by the
697 	 * caller, with the caveat (in the code above) that "size" >= the
698 	 * max. size (max_size) ends up getting recorded as a call to
699 	 * max_size.
700 	 */
701 	ctx->stats[size].gets++;
702 	ctx->stats[size].totalgets++;
703 	ctx->stats[new_size].freefrags--;
704 	ctx->inuse += new_size;
705 
706  done:
707 
708 #if ISC_MEM_FILL
709 	if (ret != NULL)
710 		memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */
711 #endif
712 
713 	return (ret);
714 }
715 
716 #if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN
717 static inline void
check_overrun(void * mem,size_t size,size_t new_size)718 check_overrun(void *mem, size_t size, size_t new_size) {
719 	unsigned char *cp;
720 
721 	cp = (unsigned char *)mem;
722 	cp += size;
723 	while (size < new_size) {
724 		INSIST(*cp == 0xbe);
725 		cp++;
726 		size++;
727 	}
728 }
729 #endif
730 
731 /* coverity[+free : arg-1] */
732 static inline void
mem_putunlocked(isc__mem_t * ctx,void * mem,size_t size)733 mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) {
734 	size_t new_size = quantize(size);
735 
736 	if (size == ctx->max_size || new_size >= ctx->max_size) {
737 		/*
738 		 * memput() called on something beyond our upper limit.
739 		 */
740 #if ISC_MEM_FILL
741 		memset(mem, 0xde, size); /* Mnemonic for "dead". */
742 #endif
743 		(ctx->memfree)(ctx->arg, mem);
744 		INSIST(ctx->stats[ctx->max_size].gets != 0U);
745 		ctx->stats[ctx->max_size].gets--;
746 		INSIST(size <= ctx->inuse);
747 		ctx->inuse -= size;
748 		return;
749 	}
750 
751 #if ISC_MEM_FILL
752 #if ISC_MEM_CHECKOVERRUN
753 	check_overrun(mem, size, new_size);
754 #endif
755 	memset(mem, 0xde, new_size); /* Mnemonic for "dead". */
756 #endif
757 
758 	/*
759 	 * The free list uses the "rounded-up" size "new_size".
760 	 */
761 	((element *)mem)->next = ctx->freelists[new_size];
762 	ctx->freelists[new_size] = (element *)mem;
763 
764 	/*
765 	 * The stats[] uses the _actual_ "size" requested by the
766 	 * caller, with the caveat (in the code above) that "size" >= the
767 	 * max. size (max_size) ends up getting recorded as a call to
768 	 * max_size.
769 	 */
770 	INSIST(ctx->stats[size].gets != 0U);
771 	ctx->stats[size].gets--;
772 	ctx->stats[new_size].freefrags++;
773 	ctx->inuse -= new_size;
774 }
775 
776 /*!
777  * Perform a malloc, doing memory filling and overrun detection as necessary.
778  */
779 static inline void *
mem_get(isc__mem_t * ctx,size_t size)780 mem_get(isc__mem_t *ctx, size_t size) {
781 	char *ret;
782 
783 #if ISC_MEM_CHECKOVERRUN
784 	size += 1;
785 #endif
786 
787 	ret = (ctx->memalloc)(ctx->arg, size);
788 	if (ret == NULL)
789 		ctx->memalloc_failures++;
790 
791 #if ISC_MEM_FILL
792 	if (ret != NULL)
793 		memset(ret, 0xbe, size); /* Mnemonic for "beef". */
794 #else
795 #  if ISC_MEM_CHECKOVERRUN
796 	if (ret != NULL)
797 		ret[size-1] = 0xbe;
798 #  endif
799 #endif
800 
801 	return (ret);
802 }
803 
804 /*!
805  * Perform a free, doing memory filling and overrun detection as necessary.
806  */
807 /* coverity[+free : arg-1] */
808 static inline void
mem_put(isc__mem_t * ctx,void * mem,size_t size)809 mem_put(isc__mem_t *ctx, void *mem, size_t size) {
810 #if ISC_MEM_CHECKOVERRUN
811 	INSIST(((unsigned char *)mem)[size] == 0xbe);
812 #endif
813 #if ISC_MEM_FILL
814 	memset(mem, 0xde, size); /* Mnemonic for "dead". */
815 #else
816 	UNUSED(size);
817 #endif
818 	(ctx->memfree)(ctx->arg, mem);
819 }
820 
821 /*!
822  * Update internal counters after a memory get.
823  */
824 static inline void
mem_getstats(isc__mem_t * ctx,size_t size)825 mem_getstats(isc__mem_t *ctx, size_t size) {
826 	ctx->total += size;
827 	ctx->inuse += size;
828 
829 	if (size > ctx->max_size) {
830 		ctx->stats[ctx->max_size].gets++;
831 		ctx->stats[ctx->max_size].totalgets++;
832 	} else {
833 		ctx->stats[size].gets++;
834 		ctx->stats[size].totalgets++;
835 	}
836 }
837 
838 /*!
839  * Update internal counters after a memory put.
840  */
841 static inline void
mem_putstats(isc__mem_t * ctx,void * ptr,size_t size)842 mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) {
843 	UNUSED(ptr);
844 
845 	INSIST(ctx->inuse >= size);
846 	ctx->inuse -= size;
847 
848 	if (size > ctx->max_size) {
849 		INSIST(ctx->stats[ctx->max_size].gets > 0U);
850 		ctx->stats[ctx->max_size].gets--;
851 	} else {
852 		INSIST(ctx->stats[size].gets > 0U);
853 		ctx->stats[size].gets--;
854 	}
855 }
856 
857 /*
858  * Private.
859  */
860 
861 static void *
default_memalloc(void * arg,size_t size)862 default_memalloc(void *arg, size_t size) {
863 	UNUSED(arg);
864 	if (size == 0U)
865 		size = 1;
866 	return (malloc(size));
867 }
868 
869 static void
default_memfree(void * arg,void * ptr)870 default_memfree(void *arg, void *ptr) {
871 	UNUSED(arg);
872 	free(ptr);
873 }
874 
875 static void
initialize_action(void)876 initialize_action(void) {
877 	RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
878 	RUNTIME_CHECK(isc_mutex_init(&contextslock) == ISC_R_SUCCESS);
879 	ISC_LIST_INIT(contexts);
880 	totallost = 0;
881 }
882 
883 /*
884  * Public.
885  */
886 
887 isc_result_t
isc_mem_createx(size_t init_max_size,size_t target_size,isc_memalloc_t memalloc,isc_memfree_t memfree,void * arg,isc_mem_t ** ctxp)888 isc_mem_createx(size_t init_max_size, size_t target_size,
889 		 isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
890 		 isc_mem_t **ctxp)
891 {
892 	return (isc_mem_createx2(init_max_size, target_size, memalloc, memfree,
893 				 arg, ctxp, ISC_MEMFLAG_DEFAULT));
894 
895 }
896 
897 isc_result_t
isc_mem_createx2(size_t init_max_size,size_t target_size,isc_memalloc_t memalloc,isc_memfree_t memfree,void * arg,isc_mem_t ** ctxp,unsigned int flags)898 isc_mem_createx2(size_t init_max_size, size_t target_size,
899 		  isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg,
900 		  isc_mem_t **ctxp, unsigned int flags)
901 {
902 	isc__mem_t *ctx;
903 	isc_result_t result;
904 
905 	REQUIRE(ctxp != NULL && *ctxp == NULL);
906 	REQUIRE(memalloc != NULL);
907 	REQUIRE(memfree != NULL);
908 
909 	INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0);
910 
911 	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
912 
913 	ctx = (memalloc)(arg, sizeof(*ctx));
914 	if (ctx == NULL)
915 		return (ISC_R_NOMEMORY);
916 
917 	if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
918 		result = isc_mutex_init(&ctx->lock);
919 		if (result != ISC_R_SUCCESS) {
920 			(memfree)(arg, ctx);
921 			return (result);
922 		}
923 	}
924 
925 	if (init_max_size == 0U)
926 		ctx->max_size = DEF_MAX_SIZE;
927 	else
928 		ctx->max_size = init_max_size;
929 	ctx->flags = flags;
930 	ctx->references = 1;
931 	memset(ctx->name, 0, sizeof(ctx->name));
932 	ctx->tag = NULL;
933 	ctx->quota = 0;
934 	ctx->total = 0;
935 	ctx->inuse = 0;
936 	ctx->maxinuse = 0;
937 	ctx->hi_water = 0;
938 	ctx->lo_water = 0;
939 	ctx->hi_called = ISC_FALSE;
940 	ctx->is_overmem = ISC_FALSE;
941 	ctx->water = NULL;
942 	ctx->water_arg = NULL;
943 	ctx->common.impmagic = MEM_MAGIC;
944 	ctx->common.magic = ISCAPI_MCTX_MAGIC;
945 	ctx->common.methods = (isc_memmethods_t *)&memmethods;
946 	isc_ondestroy_init(&ctx->ondestroy);
947 	ctx->memalloc = memalloc;
948 	ctx->memfree = memfree;
949 	ctx->arg = arg;
950 	ctx->stats = NULL;
951 	ctx->checkfree = ISC_TRUE;
952 #if ISC_MEM_TRACKLINES
953 	ctx->debuglist = NULL;
954 	ctx->debuglistcnt = 0;
955 #endif
956 	ISC_LIST_INIT(ctx->pools);
957 	ctx->poolcnt = 0;
958 	ctx->freelists = NULL;
959 	ctx->basic_blocks = NULL;
960 	ctx->basic_table = NULL;
961 	ctx->basic_table_count = 0;
962 	ctx->basic_table_size = 0;
963 	ctx->lowest = NULL;
964 	ctx->highest = NULL;
965 
966 	ctx->stats = (memalloc)(arg,
967 				(ctx->max_size+1) * sizeof(struct stats));
968 	if (ctx->stats == NULL) {
969 		result = ISC_R_NOMEMORY;
970 		goto error;
971 	}
972 	memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats));
973 
974 	if ((flags & ISC_MEMFLAG_INTERNAL) != 0) {
975 		if (target_size == 0U)
976 			ctx->mem_target = DEF_MEM_TARGET;
977 		else
978 			ctx->mem_target = target_size;
979 		ctx->freelists = (memalloc)(arg, ctx->max_size *
980 						 sizeof(element *));
981 		if (ctx->freelists == NULL) {
982 			result = ISC_R_NOMEMORY;
983 			goto error;
984 		}
985 		memset(ctx->freelists, 0,
986 		       ctx->max_size * sizeof(element *));
987 	}
988 
989 #if ISC_MEM_TRACKLINES
990 	if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
991 		unsigned int i;
992 
993 		ctx->debuglist = (memalloc)(arg,
994 				      (ctx->max_size+1) * sizeof(debuglist_t));
995 		if (ctx->debuglist == NULL) {
996 			result = ISC_R_NOMEMORY;
997 			goto error;
998 		}
999 		for (i = 0; i <= ctx->max_size; i++)
1000 			ISC_LIST_INIT(ctx->debuglist[i]);
1001 	}
1002 #endif
1003 
1004 	ctx->memalloc_failures = 0;
1005 
1006 	LOCK(&contextslock);
1007 	ISC_LIST_INITANDAPPEND(contexts, ctx, link);
1008 	UNLOCK(&contextslock);
1009 
1010 	*ctxp = (isc_mem_t *)ctx;
1011 	return (ISC_R_SUCCESS);
1012 
1013   error:
1014 	if (ctx != NULL) {
1015 		if (ctx->stats != NULL)
1016 			(memfree)(arg, ctx->stats);
1017 		if (ctx->freelists != NULL)
1018 			(memfree)(arg, ctx->freelists);
1019 #if ISC_MEM_TRACKLINES
1020 		if (ctx->debuglist != NULL)
1021 			(ctx->memfree)(ctx->arg, ctx->debuglist);
1022 #endif /* ISC_MEM_TRACKLINES */
1023 		if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1024 			DESTROYLOCK(&ctx->lock);
1025 		(memfree)(arg, ctx);
1026 	}
1027 
1028 	return (result);
1029 }
1030 
1031 static void
destroy(isc__mem_t * ctx)1032 destroy(isc__mem_t *ctx) {
1033 	unsigned int i;
1034 	isc_ondestroy_t ondest;
1035 
1036 	LOCK(&contextslock);
1037 	ISC_LIST_UNLINK(contexts, ctx, link);
1038 	totallost += ctx->inuse;
1039 	UNLOCK(&contextslock);
1040 
1041 	ctx->common.impmagic = 0;
1042 	ctx->common.magic = 0;
1043 
1044 	INSIST(ISC_LIST_EMPTY(ctx->pools));
1045 
1046 #if ISC_MEM_TRACKLINES
1047 	if (ctx->debuglist != NULL) {
1048 		if (ctx->checkfree) {
1049 			for (i = 0; i <= ctx->max_size; i++) {
1050 				if (!ISC_LIST_EMPTY(ctx->debuglist[i]))
1051 					print_active(ctx, stderr);
1052 				INSIST(ISC_LIST_EMPTY(ctx->debuglist[i]));
1053 			}
1054 		} else {
1055 			debuglink_t *dl;
1056 
1057 			for (i = 0; i <= ctx->max_size; i++)
1058 				for (dl = ISC_LIST_HEAD(ctx->debuglist[i]);
1059 				     dl != NULL;
1060 				     dl = ISC_LIST_HEAD(ctx->debuglist[i])) {
1061 					ISC_LIST_UNLINK(ctx->debuglist[i],
1062 							dl, link);
1063 					free(dl);
1064 				}
1065 		}
1066 		(ctx->memfree)(ctx->arg, ctx->debuglist);
1067 	}
1068 #endif
1069 	INSIST(ctx->references == 0);
1070 
1071 	if (ctx->checkfree) {
1072 		for (i = 0; i <= ctx->max_size; i++) {
1073 #if ISC_MEM_TRACKLINES
1074 			if (ctx->stats[i].gets != 0U)
1075 				print_active(ctx, stderr);
1076 #endif
1077 			INSIST(ctx->stats[i].gets == 0U);
1078 		}
1079 	}
1080 
1081 	(ctx->memfree)(ctx->arg, ctx->stats);
1082 
1083 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1084 		for (i = 0; i < ctx->basic_table_count; i++)
1085 			(ctx->memfree)(ctx->arg, ctx->basic_table[i]);
1086 		(ctx->memfree)(ctx->arg, ctx->freelists);
1087 		if (ctx->basic_table != NULL)
1088 			(ctx->memfree)(ctx->arg, ctx->basic_table);
1089 	}
1090 
1091 	ondest = ctx->ondestroy;
1092 
1093 	if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
1094 		DESTROYLOCK(&ctx->lock);
1095 	(ctx->memfree)(ctx->arg, ctx);
1096 
1097 	isc_ondestroy_notify(&ondest, ctx);
1098 }
1099 
1100 void
isc__mem_attach(isc_mem_t * source0,isc_mem_t ** targetp)1101 isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) {
1102 	isc__mem_t *source = (isc__mem_t *)source0;
1103 
1104 	REQUIRE(VALID_CONTEXT(source));
1105 	REQUIRE(targetp != NULL && *targetp == NULL);
1106 
1107 	MCTXLOCK(source, &source->lock);
1108 	source->references++;
1109 	MCTXUNLOCK(source, &source->lock);
1110 
1111 	*targetp = (isc_mem_t *)source;
1112 }
1113 
1114 void
isc__mem_detach(isc_mem_t ** ctxp)1115 isc__mem_detach(isc_mem_t **ctxp) {
1116 	isc__mem_t *ctx;
1117 	isc_boolean_t want_destroy = ISC_FALSE;
1118 
1119 	REQUIRE(ctxp != NULL);
1120 	ctx = (isc__mem_t *)*ctxp;
1121 	REQUIRE(VALID_CONTEXT(ctx));
1122 
1123 	MCTXLOCK(ctx, &ctx->lock);
1124 	INSIST(ctx->references > 0);
1125 	ctx->references--;
1126 	if (ctx->references == 0)
1127 		want_destroy = ISC_TRUE;
1128 	MCTXUNLOCK(ctx, &ctx->lock);
1129 
1130 	if (want_destroy)
1131 		destroy(ctx);
1132 
1133 	*ctxp = NULL;
1134 }
1135 
1136 /*
1137  * isc_mem_putanddetach() is the equivalent of:
1138  *
1139  * mctx = NULL;
1140  * isc_mem_attach(ptr->mctx, &mctx);
1141  * isc_mem_detach(&ptr->mctx);
1142  * isc_mem_put(mctx, ptr, sizeof(*ptr);
1143  * isc_mem_detach(&mctx);
1144  */
1145 
1146 void
isc___mem_putanddetach(isc_mem_t ** ctxp,void * ptr,size_t size FLARG)1147 isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) {
1148 	isc__mem_t *ctx;
1149 	isc_boolean_t want_destroy = ISC_FALSE;
1150 	size_info *si;
1151 	size_t oldsize;
1152 
1153 	REQUIRE(ctxp != NULL);
1154 	ctx = (isc__mem_t *)*ctxp;
1155 	REQUIRE(VALID_CONTEXT(ctx));
1156 	REQUIRE(ptr != NULL);
1157 
1158 	/*
1159 	 * Must be before mem_putunlocked() as ctxp is usually within
1160 	 * [ptr..ptr+size).
1161 	 */
1162 	*ctxp = NULL;
1163 
1164 	if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1165 		if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1166 			si = &(((size_info *)ptr)[-1]);
1167 			oldsize = si->u.size - ALIGNMENT_SIZE;
1168 			if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1169 				oldsize -= ALIGNMENT_SIZE;
1170 			INSIST(oldsize == size);
1171 		}
1172 		isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
1173 
1174 		MCTXLOCK(ctx, &ctx->lock);
1175 		ctx->references--;
1176 		if (ctx->references == 0)
1177 			want_destroy = ISC_TRUE;
1178 		MCTXUNLOCK(ctx, &ctx->lock);
1179 		if (want_destroy)
1180 			destroy(ctx);
1181 
1182 		return;
1183 	}
1184 
1185 	MCTXLOCK(ctx, &ctx->lock);
1186 
1187 	DELETE_TRACE(ctx, ptr, size, file, line);
1188 
1189 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1190 		mem_putunlocked(ctx, ptr, size);
1191 	} else {
1192 		mem_putstats(ctx, ptr, size);
1193 		mem_put(ctx, ptr, size);
1194 	}
1195 
1196 	INSIST(ctx->references > 0);
1197 	ctx->references--;
1198 	if (ctx->references == 0)
1199 		want_destroy = ISC_TRUE;
1200 
1201 	MCTXUNLOCK(ctx, &ctx->lock);
1202 
1203 	if (want_destroy)
1204 		destroy(ctx);
1205 }
1206 
1207 void
isc__mem_destroy(isc_mem_t ** ctxp)1208 isc__mem_destroy(isc_mem_t **ctxp) {
1209 	isc__mem_t *ctx;
1210 
1211 	/*
1212 	 * This routine provides legacy support for callers who use mctxs
1213 	 * without attaching/detaching.
1214 	 */
1215 
1216 	REQUIRE(ctxp != NULL);
1217 	ctx = (isc__mem_t *)*ctxp;
1218 	REQUIRE(VALID_CONTEXT(ctx));
1219 
1220 	MCTXLOCK(ctx, &ctx->lock);
1221 #if ISC_MEM_TRACKLINES
1222 	if (ctx->references != 1)
1223 		print_active(ctx, stderr);
1224 #endif
1225 	REQUIRE(ctx->references == 1);
1226 	ctx->references--;
1227 	MCTXUNLOCK(ctx, &ctx->lock);
1228 
1229 	destroy(ctx);
1230 
1231 	*ctxp = NULL;
1232 }
1233 
1234 isc_result_t
isc_mem_ondestroy(isc_mem_t * ctx0,isc_task_t * task,isc_event_t ** event)1235 isc_mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) {
1236 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1237 	isc_result_t res;
1238 
1239 	MCTXLOCK(ctx, &ctx->lock);
1240 	res = isc_ondestroy_register(&ctx->ondestroy, task, event);
1241 	MCTXUNLOCK(ctx, &ctx->lock);
1242 
1243 	return (res);
1244 }
1245 
1246 void *
isc___mem_get(isc_mem_t * ctx0,size_t size FLARG)1247 isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
1248 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1249 	void *ptr;
1250 	isc_boolean_t call_water = ISC_FALSE;
1251 
1252 	REQUIRE(VALID_CONTEXT(ctx));
1253 
1254 	if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0)
1255 		return (isc__mem_allocate(ctx0, size FLARG_PASS));
1256 
1257 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1258 		MCTXLOCK(ctx, &ctx->lock);
1259 		ptr = mem_getunlocked(ctx, size);
1260 	} else {
1261 		ptr = mem_get(ctx, size);
1262 		MCTXLOCK(ctx, &ctx->lock);
1263 		if (ptr != NULL)
1264 			mem_getstats(ctx, size);
1265 	}
1266 
1267 	ADD_TRACE(ctx, ptr, size, file, line);
1268 	if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1269 	    !ctx->is_overmem) {
1270 		ctx->is_overmem = ISC_TRUE;
1271 	}
1272 	if (ctx->hi_water != 0U && !ctx->hi_called &&
1273 	    ctx->inuse > ctx->hi_water) {
1274 		call_water = ISC_TRUE;
1275 	}
1276 	if (ctx->inuse > ctx->maxinuse) {
1277 		ctx->maxinuse = ctx->inuse;
1278 		if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1279 		    (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1280 			fprintf(stderr, "maxinuse = %lu\n",
1281 				(unsigned long)ctx->inuse);
1282 	}
1283 	MCTXUNLOCK(ctx, &ctx->lock);
1284 
1285 	if (call_water)
1286 		(ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1287 
1288 	return (ptr);
1289 }
1290 
1291 void
isc___mem_put(isc_mem_t * ctx0,void * ptr,size_t size FLARG)1292 isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1293 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1294 	isc_boolean_t call_water = ISC_FALSE;
1295 	size_info *si;
1296 	size_t oldsize;
1297 
1298 	REQUIRE(VALID_CONTEXT(ctx));
1299 	REQUIRE(ptr != NULL);
1300 
1301 	if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) {
1302 		if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) {
1303 			si = &(((size_info *)ptr)[-1]);
1304 			oldsize = si->u.size - ALIGNMENT_SIZE;
1305 			if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1306 				oldsize -= ALIGNMENT_SIZE;
1307 			INSIST(oldsize == size);
1308 		}
1309 		isc__mem_free((isc_mem_t *)ctx, ptr FLARG_PASS);
1310 		return;
1311 	}
1312 
1313 	MCTXLOCK(ctx, &ctx->lock);
1314 
1315 	DELETE_TRACE(ctx, ptr, size, file, line);
1316 
1317 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1318 		mem_putunlocked(ctx, ptr, size);
1319 	} else {
1320 		mem_putstats(ctx, ptr, size);
1321 		mem_put(ctx, ptr, size);
1322 	}
1323 
1324 	/*
1325 	 * The check against ctx->lo_water == 0 is for the condition
1326 	 * when the context was pushed over hi_water but then had
1327 	 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1328 	 */
1329 	if (ctx->is_overmem &&
1330 	    (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1331 		ctx->is_overmem = ISC_FALSE;
1332 	}
1333 	if (ctx->hi_called &&
1334 	    (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1335 		if (ctx->water != NULL)
1336 			call_water = ISC_TRUE;
1337 	}
1338 	MCTXUNLOCK(ctx, &ctx->lock);
1339 
1340 	if (call_water)
1341 		(ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1342 }
1343 
1344 void
isc__mem_waterack(isc_mem_t * ctx0,int flag)1345 isc__mem_waterack(isc_mem_t *ctx0, int flag) {
1346 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1347 
1348 	REQUIRE(VALID_CONTEXT(ctx));
1349 
1350 	MCTXLOCK(ctx, &ctx->lock);
1351 	if (flag == ISC_MEM_LOWATER)
1352 		ctx->hi_called = ISC_FALSE;
1353 	else if (flag == ISC_MEM_HIWATER)
1354 		ctx->hi_called = ISC_TRUE;
1355 	MCTXUNLOCK(ctx, &ctx->lock);
1356 }
1357 
1358 #if ISC_MEM_TRACKLINES
1359 static void
print_active(isc__mem_t * mctx,FILE * out)1360 print_active(isc__mem_t *mctx, FILE *out) {
1361 	if (mctx->debuglist != NULL) {
1362 		debuglink_t *dl;
1363 		unsigned int i, j;
1364 		const char *format;
1365 		isc_boolean_t found;
1366 
1367 		fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1368 					    ISC_MSG_DUMPALLOC,
1369 					    "Dump of all outstanding "
1370 					    "memory allocations:\n"));
1371 		found = ISC_FALSE;
1372 		format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1373 					ISC_MSG_PTRFILELINE,
1374 					"\tptr %p size %u file %s line %u\n");
1375 		for (i = 0; i <= mctx->max_size; i++) {
1376 			dl = ISC_LIST_HEAD(mctx->debuglist[i]);
1377 
1378 			if (dl != NULL)
1379 				found = ISC_TRUE;
1380 
1381 			while (dl != NULL) {
1382 				for (j = 0; j < DEBUGLIST_COUNT; j++)
1383 					if (dl->ptr[j] != NULL)
1384 						fprintf(out, format,
1385 							dl->ptr[j],
1386 							dl->size[j],
1387 							dl->file[j],
1388 							dl->line[j]);
1389 				dl = ISC_LIST_NEXT(dl, link);
1390 			}
1391 		}
1392 		if (!found)
1393 			fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1394 						    ISC_MSG_NONE, "\tNone.\n"));
1395 	}
1396 }
1397 #endif
1398 
1399 /*
1400  * Print the stats[] on the stream "out" with suitable formatting.
1401  */
1402 void
isc_mem_stats(isc_mem_t * ctx0,FILE * out)1403 isc_mem_stats(isc_mem_t *ctx0, FILE *out) {
1404 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1405 	size_t i;
1406 	const struct stats *s;
1407 	const isc__mempool_t *pool;
1408 
1409 	REQUIRE(VALID_CONTEXT(ctx));
1410 	MCTXLOCK(ctx, &ctx->lock);
1411 
1412 	for (i = 0; i <= ctx->max_size; i++) {
1413 		s = &ctx->stats[i];
1414 
1415 		if (s->totalgets == 0U && s->gets == 0U)
1416 			continue;
1417 		fprintf(out, "%s%5lu: %11lu gets, %11lu rem",
1418 			(i == ctx->max_size) ? ">=" : "  ",
1419 			(unsigned long) i, s->totalgets, s->gets);
1420 		if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 &&
1421 		    (s->blocks != 0U || s->freefrags != 0U))
1422 			fprintf(out, " (%lu bl, %lu ff)",
1423 				s->blocks, s->freefrags);
1424 		fputc('\n', out);
1425 	}
1426 
1427 	/*
1428 	 * Note that since a pool can be locked now, these stats might be
1429 	 * somewhat off if the pool is in active use at the time the stats
1430 	 * are dumped.  The link fields are protected by the isc_mem_t's
1431 	 * lock, however, so walking this list and extracting integers from
1432 	 * stats fields is always safe.
1433 	 */
1434 	pool = ISC_LIST_HEAD(ctx->pools);
1435 	if (pool != NULL) {
1436 		fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1437 					    ISC_MSG_POOLSTATS,
1438 					    "[Pool statistics]\n"));
1439 		fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n",
1440 			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1441 				       ISC_MSG_POOLNAME, "name"),
1442 			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1443 				       ISC_MSG_POOLSIZE, "size"),
1444 			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1445 				       ISC_MSG_POOLMAXALLOC, "maxalloc"),
1446 			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1447 				       ISC_MSG_POOLALLOCATED, "allocated"),
1448 			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1449 				       ISC_MSG_POOLFREECOUNT, "freecount"),
1450 			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1451 				       ISC_MSG_POOLFREEMAX, "freemax"),
1452 			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1453 				       ISC_MSG_POOLFILLCOUNT, "fillcount"),
1454 			isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM,
1455 				       ISC_MSG_POOLGETS, "gets"),
1456 			"L");
1457 	}
1458 	while (pool != NULL) {
1459 		fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n",
1460 #if ISC_MEMPOOL_NAMES
1461 			pool->name,
1462 #else
1463 			"(not tracked)",
1464 #endif
1465 			(unsigned long) pool->size, pool->maxalloc,
1466 			pool->allocated, pool->freecount, pool->freemax,
1467 			pool->fillcount, pool->gets,
1468 			(pool->lock == NULL ? "N" : "Y"));
1469 		pool = ISC_LIST_NEXT(pool, link);
1470 	}
1471 
1472 #if ISC_MEM_TRACKLINES
1473 	print_active(ctx, out);
1474 #endif
1475 
1476 	MCTXUNLOCK(ctx, &ctx->lock);
1477 }
1478 
1479 /*
1480  * Replacements for malloc() and free() -- they implicitly remember the
1481  * size of the object allocated (with some additional overhead).
1482  */
1483 
1484 static void *
mem_allocateunlocked(isc_mem_t * ctx0,size_t size)1485 mem_allocateunlocked(isc_mem_t *ctx0, size_t size) {
1486 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1487 	size_info *si;
1488 
1489 	size += ALIGNMENT_SIZE;
1490 	if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0)
1491 		size += ALIGNMENT_SIZE;
1492 
1493 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
1494 		si = mem_getunlocked(ctx, size);
1495 	else
1496 		si = mem_get(ctx, size);
1497 
1498 	if (si == NULL)
1499 		return (NULL);
1500 	if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1501 		si->u.ctx = ctx;
1502 		si++;
1503 	}
1504 	si->u.size = size;
1505 	return (&si[1]);
1506 }
1507 
1508 void *
isc___mem_allocate(isc_mem_t * ctx0,size_t size FLARG)1509 isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
1510 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1511 	size_info *si;
1512 	isc_boolean_t call_water = ISC_FALSE;
1513 
1514 	REQUIRE(VALID_CONTEXT(ctx));
1515 
1516 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1517 		MCTXLOCK(ctx, &ctx->lock);
1518 		si = mem_allocateunlocked((isc_mem_t *)ctx, size);
1519 	} else {
1520 		si = mem_allocateunlocked((isc_mem_t *)ctx, size);
1521 		MCTXLOCK(ctx, &ctx->lock);
1522 		if (si != NULL)
1523 			mem_getstats(ctx, si[-1].u.size);
1524 	}
1525 
1526 #if ISC_MEM_TRACKLINES
1527 	ADD_TRACE(ctx, si, si[-1].u.size, file, line);
1528 #endif
1529 	if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1530 	    !ctx->is_overmem) {
1531 		ctx->is_overmem = ISC_TRUE;
1532 	}
1533 
1534 	if (ctx->hi_water != 0U && !ctx->hi_called &&
1535 	    ctx->inuse > ctx->hi_water) {
1536 		ctx->hi_called = ISC_TRUE;
1537 		call_water = ISC_TRUE;
1538 	}
1539 	if (ctx->inuse > ctx->maxinuse) {
1540 		ctx->maxinuse = ctx->inuse;
1541 		if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
1542 		    (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0)
1543 			fprintf(stderr, "maxinuse = %lu\n",
1544 				(unsigned long)ctx->inuse);
1545 	}
1546 	MCTXUNLOCK(ctx, &ctx->lock);
1547 
1548 	if (call_water)
1549 		(ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
1550 
1551 	return (si);
1552 }
1553 
1554 void *
isc___mem_reallocate(isc_mem_t * ctx0,void * ptr,size_t size FLARG)1555 isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
1556 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1557 	void *new_ptr = NULL;
1558 	size_t oldsize, copysize;
1559 
1560 	REQUIRE(VALID_CONTEXT(ctx));
1561 
1562 	/*
1563 	 * This function emulates the realloc(3) standard library function:
1564 	 * - if size > 0, allocate new memory; and if ptr is non NULL, copy
1565 	 *   as much of the old contents to the new buffer and free the old one.
1566 	 *   Note that when allocation fails the original pointer is intact;
1567 	 *   the caller must free it.
1568 	 * - if size is 0 and ptr is non NULL, simply free the given ptr.
1569 	 * - this function returns:
1570 	 *     pointer to the newly allocated memory, or
1571 	 *     NULL if allocation fails or doesn't happen.
1572 	 */
1573 	if (size > 0U) {
1574 		new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS);
1575 		if (new_ptr != NULL && ptr != NULL) {
1576 			oldsize = (((size_info *)ptr)[-1]).u.size;
1577 			INSIST(oldsize >= ALIGNMENT_SIZE);
1578 			oldsize -= ALIGNMENT_SIZE;
1579 			if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1580 				INSIST(oldsize >= ALIGNMENT_SIZE);
1581 				oldsize -= ALIGNMENT_SIZE;
1582 			}
1583 			copysize = (oldsize > size) ? size : oldsize;
1584 			memmove(new_ptr, ptr, copysize);
1585 			isc__mem_free(ctx0, ptr FLARG_PASS);
1586 		}
1587 	} else if (ptr != NULL)
1588 		isc__mem_free(ctx0, ptr FLARG_PASS);
1589 
1590 	return (new_ptr);
1591 }
1592 
1593 void
isc___mem_free(isc_mem_t * ctx0,void * ptr FLARG)1594 isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
1595 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1596 	size_info *si;
1597 	size_t size;
1598 	isc_boolean_t call_water= ISC_FALSE;
1599 
1600 	REQUIRE(VALID_CONTEXT(ctx));
1601 	REQUIRE(ptr != NULL);
1602 
1603 	if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) {
1604 		si = &(((size_info *)ptr)[-2]);
1605 		REQUIRE(si->u.ctx == ctx);
1606 		size = si[1].u.size;
1607 	} else {
1608 		si = &(((size_info *)ptr)[-1]);
1609 		size = si->u.size;
1610 	}
1611 
1612 	MCTXLOCK(ctx, &ctx->lock);
1613 
1614 	DELETE_TRACE(ctx, ptr, size, file, line);
1615 
1616 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1617 		mem_putunlocked(ctx, si, size);
1618 	} else {
1619 		mem_putstats(ctx, si, size);
1620 		mem_put(ctx, si, size);
1621 	}
1622 
1623 	/*
1624 	 * The check against ctx->lo_water == 0 is for the condition
1625 	 * when the context was pushed over hi_water but then had
1626 	 * isc_mem_setwater() called with 0 for hi_water and lo_water.
1627 	 */
1628 	if (ctx->is_overmem &&
1629 	    (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1630 		ctx->is_overmem = ISC_FALSE;
1631 	}
1632 
1633 	if (ctx->hi_called &&
1634 	    (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
1635 		ctx->hi_called = ISC_FALSE;
1636 
1637 		if (ctx->water != NULL)
1638 			call_water = ISC_TRUE;
1639 	}
1640 	MCTXUNLOCK(ctx, &ctx->lock);
1641 
1642 	if (call_water)
1643 		(ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
1644 }
1645 
1646 
1647 /*
1648  * Other useful things.
1649  */
1650 
1651 char *
isc___mem_strdup(isc_mem_t * mctx0,const char * s FLARG)1652 isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) {
1653 	isc__mem_t *mctx = (isc__mem_t *)mctx0;
1654 	size_t len;
1655 	char *ns;
1656 
1657 	REQUIRE(VALID_CONTEXT(mctx));
1658 	REQUIRE(s != NULL);
1659 
1660 	len = strlen(s);
1661 
1662 	ns = isc__mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS);
1663 
1664 	if (ns != NULL)
1665 		strncpy(ns, s, len + 1);
1666 
1667 	return (ns);
1668 }
1669 
1670 void
isc__mem_setdestroycheck(isc_mem_t * ctx0,isc_boolean_t flag)1671 isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) {
1672 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1673 
1674 	REQUIRE(VALID_CONTEXT(ctx));
1675 	MCTXLOCK(ctx, &ctx->lock);
1676 
1677 	ctx->checkfree = flag;
1678 
1679 	MCTXUNLOCK(ctx, &ctx->lock);
1680 }
1681 
1682 /*
1683  * Quotas
1684  */
1685 
1686 void
isc_mem_setquota(isc_mem_t * ctx0,size_t quota)1687 isc_mem_setquota(isc_mem_t *ctx0, size_t quota) {
1688 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1689 
1690 	REQUIRE(VALID_CONTEXT(ctx));
1691 	MCTXLOCK(ctx, &ctx->lock);
1692 
1693 	ctx->quota = quota;
1694 
1695 	MCTXUNLOCK(ctx, &ctx->lock);
1696 }
1697 
1698 size_t
isc_mem_getquota(isc_mem_t * ctx0)1699 isc_mem_getquota(isc_mem_t *ctx0) {
1700 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1701 	size_t quota;
1702 
1703 	REQUIRE(VALID_CONTEXT(ctx));
1704 	MCTXLOCK(ctx, &ctx->lock);
1705 
1706 	quota = ctx->quota;
1707 
1708 	MCTXUNLOCK(ctx, &ctx->lock);
1709 
1710 	return (quota);
1711 }
1712 
1713 size_t
isc__mem_inuse(isc_mem_t * ctx0)1714 isc__mem_inuse(isc_mem_t *ctx0) {
1715 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1716 	size_t inuse;
1717 
1718 	REQUIRE(VALID_CONTEXT(ctx));
1719 	MCTXLOCK(ctx, &ctx->lock);
1720 
1721 	inuse = ctx->inuse;
1722 
1723 	MCTXUNLOCK(ctx, &ctx->lock);
1724 
1725 	return (inuse);
1726 }
1727 
1728 size_t
isc__mem_maxinuse(isc_mem_t * ctx0)1729 isc__mem_maxinuse(isc_mem_t *ctx0) {
1730 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1731 	size_t maxinuse;
1732 
1733 	REQUIRE(VALID_CONTEXT(ctx));
1734 	MCTXLOCK(ctx, &ctx->lock);
1735 
1736 	maxinuse = ctx->maxinuse;
1737 
1738 	MCTXUNLOCK(ctx, &ctx->lock);
1739 
1740 	return (maxinuse);
1741 }
1742 
1743 size_t
isc__mem_total(isc_mem_t * ctx0)1744 isc__mem_total(isc_mem_t *ctx0) {
1745 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1746 	size_t total;
1747 
1748 	REQUIRE(VALID_CONTEXT(ctx));
1749 	MCTXLOCK(ctx, &ctx->lock);
1750 
1751 	total = ctx->total;
1752 
1753 	MCTXUNLOCK(ctx, &ctx->lock);
1754 
1755 	return (total);
1756 }
1757 
1758 void
isc__mem_setwater(isc_mem_t * ctx0,isc_mem_water_t water,void * water_arg,size_t hiwater,size_t lowater)1759 isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg,
1760 		  size_t hiwater, size_t lowater)
1761 {
1762 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1763 	isc_boolean_t callwater = ISC_FALSE;
1764 	isc_mem_water_t oldwater;
1765 	void *oldwater_arg;
1766 
1767 	REQUIRE(VALID_CONTEXT(ctx));
1768 	REQUIRE(hiwater >= lowater);
1769 
1770 	MCTXLOCK(ctx, &ctx->lock);
1771 	oldwater = ctx->water;
1772 	oldwater_arg = ctx->water_arg;
1773 	if (water == NULL) {
1774 		callwater = ctx->hi_called;
1775 		ctx->water = NULL;
1776 		ctx->water_arg = NULL;
1777 		ctx->hi_water = 0;
1778 		ctx->lo_water = 0;
1779 		ctx->hi_called = ISC_FALSE;
1780 	} else {
1781 		if (ctx->hi_called &&
1782 		    (ctx->water != water || ctx->water_arg != water_arg ||
1783 		     ctx->inuse < lowater || lowater == 0U))
1784 			callwater = ISC_TRUE;
1785 		ctx->water = water;
1786 		ctx->water_arg = water_arg;
1787 		ctx->hi_water = hiwater;
1788 		ctx->lo_water = lowater;
1789 	}
1790 	MCTXUNLOCK(ctx, &ctx->lock);
1791 
1792 	if (callwater && oldwater != NULL)
1793 		(oldwater)(oldwater_arg, ISC_MEM_LOWATER);
1794 }
1795 
1796 isc_boolean_t
isc__mem_isovermem(isc_mem_t * ctx0)1797 isc__mem_isovermem(isc_mem_t *ctx0) {
1798 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1799 
1800 	REQUIRE(VALID_CONTEXT(ctx));
1801 
1802 	/*
1803 	 * We don't bother to lock the context because 100% accuracy isn't
1804 	 * necessary (and even if we locked the context the returned value
1805 	 * could be different from the actual state when it's used anyway)
1806 	 */
1807 	return (ctx->is_overmem);
1808 }
1809 
1810 void
isc_mem_setname(isc_mem_t * ctx0,const char * name,void * tag)1811 isc_mem_setname(isc_mem_t *ctx0, const char *name, void *tag) {
1812 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1813 
1814 	REQUIRE(VALID_CONTEXT(ctx));
1815 
1816 	LOCK(&ctx->lock);
1817 	memset(ctx->name, 0, sizeof(ctx->name));
1818 	strncpy(ctx->name, name, sizeof(ctx->name) - 1);
1819 	ctx->tag = tag;
1820 	UNLOCK(&ctx->lock);
1821 }
1822 
1823 const char *
isc_mem_getname(isc_mem_t * ctx0)1824 isc_mem_getname(isc_mem_t *ctx0) {
1825 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1826 
1827 	REQUIRE(VALID_CONTEXT(ctx));
1828 
1829 	if (ctx->name[0] == 0)
1830 		return ("");
1831 
1832 	return (ctx->name);
1833 }
1834 
1835 void *
isc_mem_gettag(isc_mem_t * ctx0)1836 isc_mem_gettag(isc_mem_t *ctx0) {
1837 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
1838 
1839 	REQUIRE(VALID_CONTEXT(ctx));
1840 
1841 	return (ctx->tag);
1842 }
1843 
1844 /*
1845  * Memory pool stuff
1846  */
1847 
1848 isc_result_t
isc__mempool_create(isc_mem_t * mctx0,size_t size,isc_mempool_t ** mpctxp)1849 isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) {
1850 	isc__mem_t *mctx = (isc__mem_t *)mctx0;
1851 	isc__mempool_t *mpctx;
1852 
1853 	REQUIRE(VALID_CONTEXT(mctx));
1854 	REQUIRE(size > 0U);
1855 	REQUIRE(mpctxp != NULL && *mpctxp == NULL);
1856 
1857 	/*
1858 	 * Allocate space for this pool, initialize values, and if all works
1859 	 * well, attach to the memory context.
1860 	 */
1861 	mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t));
1862 	if (mpctx == NULL)
1863 		return (ISC_R_NOMEMORY);
1864 
1865 	mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods;
1866 	mpctx->common.impmagic = MEMPOOL_MAGIC;
1867 	mpctx->common.magic = ISCAPI_MPOOL_MAGIC;
1868 	mpctx->lock = NULL;
1869 	mpctx->mctx = mctx;
1870 	mpctx->size = size;
1871 	mpctx->maxalloc = UINT_MAX;
1872 	mpctx->allocated = 0;
1873 	mpctx->freecount = 0;
1874 	mpctx->freemax = 1;
1875 	mpctx->fillcount = 1;
1876 	mpctx->gets = 0;
1877 #if ISC_MEMPOOL_NAMES
1878 	mpctx->name[0] = 0;
1879 #endif
1880 	mpctx->items = NULL;
1881 
1882 	*mpctxp = (isc_mempool_t *)mpctx;
1883 
1884 	MCTXLOCK(mctx, &mctx->lock);
1885 	ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
1886 	mctx->poolcnt++;
1887 	MCTXUNLOCK(mctx, &mctx->lock);
1888 
1889 	return (ISC_R_SUCCESS);
1890 }
1891 
1892 void
isc__mempool_setname(isc_mempool_t * mpctx0,const char * name)1893 isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) {
1894 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1895 
1896 	REQUIRE(name != NULL);
1897 	REQUIRE(VALID_MEMPOOL(mpctx));
1898 
1899 #if ISC_MEMPOOL_NAMES
1900 	if (mpctx->lock != NULL)
1901 		LOCK(mpctx->lock);
1902 
1903 	strncpy(mpctx->name, name, sizeof(mpctx->name) - 1);
1904 	mpctx->name[sizeof(mpctx->name) - 1] = '\0';
1905 
1906 	if (mpctx->lock != NULL)
1907 		UNLOCK(mpctx->lock);
1908 #else
1909 	UNUSED(mpctx);
1910 	UNUSED(name);
1911 #endif
1912 }
1913 
1914 void
isc__mempool_destroy(isc_mempool_t ** mpctxp)1915 isc__mempool_destroy(isc_mempool_t **mpctxp) {
1916 	isc__mempool_t *mpctx;
1917 	isc__mem_t *mctx;
1918 	isc_mutex_t *lock;
1919 	element *item;
1920 
1921 	REQUIRE(mpctxp != NULL);
1922 	mpctx = (isc__mempool_t *)*mpctxp;
1923 	REQUIRE(VALID_MEMPOOL(mpctx));
1924 #if ISC_MEMPOOL_NAMES
1925 	if (mpctx->allocated > 0)
1926 		UNEXPECTED_ERROR(__FILE__, __LINE__,
1927 				 "isc__mempool_destroy(): mempool %s "
1928 				 "leaked memory",
1929 				 mpctx->name);
1930 #endif
1931 	REQUIRE(mpctx->allocated == 0);
1932 
1933 	mctx = mpctx->mctx;
1934 
1935 	lock = mpctx->lock;
1936 
1937 	if (lock != NULL)
1938 		LOCK(lock);
1939 
1940 	/*
1941 	 * Return any items on the free list
1942 	 */
1943 	MCTXLOCK(mctx, &mctx->lock);
1944 	while (mpctx->items != NULL) {
1945 		INSIST(mpctx->freecount > 0);
1946 		mpctx->freecount--;
1947 		item = mpctx->items;
1948 		mpctx->items = item->next;
1949 
1950 		if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
1951 			mem_putunlocked(mctx, item, mpctx->size);
1952 		} else {
1953 			mem_putstats(mctx, item, mpctx->size);
1954 			mem_put(mctx, item, mpctx->size);
1955 		}
1956 	}
1957 	MCTXUNLOCK(mctx, &mctx->lock);
1958 
1959 	/*
1960 	 * Remove our linked list entry from the memory context.
1961 	 */
1962 	MCTXLOCK(mctx, &mctx->lock);
1963 	ISC_LIST_UNLINK(mctx->pools, mpctx, link);
1964 	mctx->poolcnt--;
1965 	MCTXUNLOCK(mctx, &mctx->lock);
1966 
1967 	mpctx->common.impmagic = 0;
1968 	mpctx->common.magic = 0;
1969 
1970 	isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t));
1971 
1972 	if (lock != NULL)
1973 		UNLOCK(lock);
1974 
1975 	*mpctxp = NULL;
1976 }
1977 
1978 void
isc__mempool_associatelock(isc_mempool_t * mpctx0,isc_mutex_t * lock)1979 isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) {
1980 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1981 
1982 	REQUIRE(VALID_MEMPOOL(mpctx));
1983 	REQUIRE(mpctx->lock == NULL);
1984 	REQUIRE(lock != NULL);
1985 
1986 	mpctx->lock = lock;
1987 }
1988 
1989 void *
isc___mempool_get(isc_mempool_t * mpctx0 FLARG)1990 isc___mempool_get(isc_mempool_t *mpctx0 FLARG) {
1991 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
1992 	element *item;
1993 	isc__mem_t *mctx;
1994 	unsigned int i;
1995 
1996 	REQUIRE(VALID_MEMPOOL(mpctx));
1997 
1998 	mctx = mpctx->mctx;
1999 
2000 	if (mpctx->lock != NULL)
2001 		LOCK(mpctx->lock);
2002 
2003 	/*
2004 	 * Don't let the caller go over quota
2005 	 */
2006 	if (mpctx->allocated >= mpctx->maxalloc) {
2007 		item = NULL;
2008 		goto out;
2009 	}
2010 
2011 	/*
2012 	 * if we have a free list item, return the first here
2013 	 */
2014 	item = mpctx->items;
2015 	if (item != NULL) {
2016 		mpctx->items = item->next;
2017 		INSIST(mpctx->freecount > 0);
2018 		mpctx->freecount--;
2019 		mpctx->gets++;
2020 		mpctx->allocated++;
2021 		goto out;
2022 	}
2023 
2024 	/*
2025 	 * We need to dip into the well.  Lock the memory context here and
2026 	 * fill up our free list.
2027 	 */
2028 	MCTXLOCK(mctx, &mctx->lock);
2029 	for (i = 0; i < mpctx->fillcount; i++) {
2030 		if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2031 			item = mem_getunlocked(mctx, mpctx->size);
2032 		} else {
2033 			item = mem_get(mctx, mpctx->size);
2034 			if (item != NULL)
2035 				mem_getstats(mctx, mpctx->size);
2036 		}
2037 		if (item == NULL)
2038 			break;
2039 		item->next = mpctx->items;
2040 		mpctx->items = item;
2041 		mpctx->freecount++;
2042 	}
2043 	MCTXUNLOCK(mctx, &mctx->lock);
2044 
2045 	/*
2046 	 * If we didn't get any items, return NULL.
2047 	 */
2048 	item = mpctx->items;
2049 	if (item == NULL)
2050 		goto out;
2051 
2052 	mpctx->items = item->next;
2053 	mpctx->freecount--;
2054 	mpctx->gets++;
2055 	mpctx->allocated++;
2056 
2057  out:
2058 	if (mpctx->lock != NULL)
2059 		UNLOCK(mpctx->lock);
2060 
2061 #if ISC_MEM_TRACKLINES
2062 	if (item != NULL) {
2063 		MCTXLOCK(mctx, &mctx->lock);
2064 		ADD_TRACE(mctx, item, mpctx->size, file, line);
2065 		MCTXUNLOCK(mctx, &mctx->lock);
2066 	}
2067 #endif /* ISC_MEM_TRACKLINES */
2068 
2069 	return (item);
2070 }
2071 
2072 /* coverity[+free : arg-1] */
2073 void
isc___mempool_put(isc_mempool_t * mpctx0,void * mem FLARG)2074 isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) {
2075 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2076 	isc__mem_t *mctx;
2077 	element *item;
2078 
2079 	REQUIRE(VALID_MEMPOOL(mpctx));
2080 	REQUIRE(mem != NULL);
2081 
2082 	mctx = mpctx->mctx;
2083 
2084 	if (mpctx->lock != NULL)
2085 		LOCK(mpctx->lock);
2086 
2087 	INSIST(mpctx->allocated > 0);
2088 	mpctx->allocated--;
2089 
2090 #if ISC_MEM_TRACKLINES
2091 	MCTXLOCK(mctx, &mctx->lock);
2092 	DELETE_TRACE(mctx, mem, mpctx->size, file, line);
2093 	MCTXUNLOCK(mctx, &mctx->lock);
2094 #endif /* ISC_MEM_TRACKLINES */
2095 
2096 	/*
2097 	 * If our free list is full, return this to the mctx directly.
2098 	 */
2099 	if (mpctx->freecount >= mpctx->freemax) {
2100 		MCTXLOCK(mctx, &mctx->lock);
2101 		if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2102 			mem_putunlocked(mctx, mem, mpctx->size);
2103 		} else {
2104 			mem_putstats(mctx, mem, mpctx->size);
2105 			mem_put(mctx, mem, mpctx->size);
2106 		}
2107 		MCTXUNLOCK(mctx, &mctx->lock);
2108 		if (mpctx->lock != NULL)
2109 			UNLOCK(mpctx->lock);
2110 		return;
2111 	}
2112 
2113 	/*
2114 	 * Otherwise, attach it to our free list and bump the counter.
2115 	 */
2116 	mpctx->freecount++;
2117 	item = (element *)mem;
2118 	item->next = mpctx->items;
2119 	mpctx->items = item;
2120 
2121 	if (mpctx->lock != NULL)
2122 		UNLOCK(mpctx->lock);
2123 }
2124 
2125 /*
2126  * Quotas
2127  */
2128 
2129 void
isc__mempool_setfreemax(isc_mempool_t * mpctx0,unsigned int limit)2130 isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) {
2131 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2132 
2133 	REQUIRE(VALID_MEMPOOL(mpctx));
2134 
2135 	if (mpctx->lock != NULL)
2136 		LOCK(mpctx->lock);
2137 
2138 	mpctx->freemax = limit;
2139 
2140 	if (mpctx->lock != NULL)
2141 		UNLOCK(mpctx->lock);
2142 }
2143 
2144 unsigned int
isc_mempool_getfreemax(isc_mempool_t * mpctx0)2145 isc_mempool_getfreemax(isc_mempool_t *mpctx0) {
2146 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2147 	unsigned int freemax;
2148 
2149 	REQUIRE(VALID_MEMPOOL(mpctx));
2150 
2151 	if (mpctx->lock != NULL)
2152 		LOCK(mpctx->lock);
2153 
2154 	freemax = mpctx->freemax;
2155 
2156 	if (mpctx->lock != NULL)
2157 		UNLOCK(mpctx->lock);
2158 
2159 	return (freemax);
2160 }
2161 
2162 unsigned int
isc_mempool_getfreecount(isc_mempool_t * mpctx0)2163 isc_mempool_getfreecount(isc_mempool_t *mpctx0) {
2164 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2165 	unsigned int freecount;
2166 
2167 	REQUIRE(VALID_MEMPOOL(mpctx));
2168 
2169 	if (mpctx->lock != NULL)
2170 		LOCK(mpctx->lock);
2171 
2172 	freecount = mpctx->freecount;
2173 
2174 	if (mpctx->lock != NULL)
2175 		UNLOCK(mpctx->lock);
2176 
2177 	return (freecount);
2178 }
2179 
2180 void
isc__mempool_setmaxalloc(isc_mempool_t * mpctx0,unsigned int limit)2181 isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) {
2182 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2183 
2184 	REQUIRE(limit > 0);
2185 
2186 	REQUIRE(VALID_MEMPOOL(mpctx));
2187 
2188 	if (mpctx->lock != NULL)
2189 		LOCK(mpctx->lock);
2190 
2191 	mpctx->maxalloc = limit;
2192 
2193 	if (mpctx->lock != NULL)
2194 		UNLOCK(mpctx->lock);
2195 }
2196 
2197 unsigned int
isc_mempool_getmaxalloc(isc_mempool_t * mpctx0)2198 isc_mempool_getmaxalloc(isc_mempool_t *mpctx0) {
2199 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2200 	unsigned int maxalloc;
2201 
2202 	REQUIRE(VALID_MEMPOOL(mpctx));
2203 
2204 	if (mpctx->lock != NULL)
2205 		LOCK(mpctx->lock);
2206 
2207 	maxalloc = mpctx->maxalloc;
2208 
2209 	if (mpctx->lock != NULL)
2210 		UNLOCK(mpctx->lock);
2211 
2212 	return (maxalloc);
2213 }
2214 
2215 unsigned int
isc__mempool_getallocated(isc_mempool_t * mpctx0)2216 isc__mempool_getallocated(isc_mempool_t *mpctx0) {
2217 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2218 	unsigned int allocated;
2219 
2220 	REQUIRE(VALID_MEMPOOL(mpctx));
2221 
2222 	if (mpctx->lock != NULL)
2223 		LOCK(mpctx->lock);
2224 
2225 	allocated = mpctx->allocated;
2226 
2227 	if (mpctx->lock != NULL)
2228 		UNLOCK(mpctx->lock);
2229 
2230 	return (allocated);
2231 }
2232 
2233 void
isc__mempool_setfillcount(isc_mempool_t * mpctx0,unsigned int limit)2234 isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) {
2235 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2236 
2237 	REQUIRE(limit > 0);
2238 	REQUIRE(VALID_MEMPOOL(mpctx));
2239 
2240 	if (mpctx->lock != NULL)
2241 		LOCK(mpctx->lock);
2242 
2243 	mpctx->fillcount = limit;
2244 
2245 	if (mpctx->lock != NULL)
2246 		UNLOCK(mpctx->lock);
2247 }
2248 
2249 unsigned int
isc_mempool_getfillcount(isc_mempool_t * mpctx0)2250 isc_mempool_getfillcount(isc_mempool_t *mpctx0) {
2251 	isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0;
2252 
2253 	unsigned int fillcount;
2254 
2255 	REQUIRE(VALID_MEMPOOL(mpctx));
2256 
2257 	if (mpctx->lock != NULL)
2258 		LOCK(mpctx->lock);
2259 
2260 	fillcount = mpctx->fillcount;
2261 
2262 	if (mpctx->lock != NULL)
2263 		UNLOCK(mpctx->lock);
2264 
2265 	return (fillcount);
2266 }
2267 
2268 isc_result_t
isc__mem_register(void)2269 isc__mem_register(void) {
2270 	return (isc_mem_register(isc_mem_create2));
2271 }
2272 
2273 void
isc__mem_printactive(isc_mem_t * ctx0,FILE * file)2274 isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
2275 #if ISC_MEM_TRACKLINES
2276 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
2277 
2278 	REQUIRE(VALID_CONTEXT(ctx));
2279 	REQUIRE(file != NULL);
2280 
2281 	print_active(ctx, file);
2282 #else
2283 	UNUSED(ctx0);
2284 	UNUSED(file);
2285 #endif
2286 }
2287 
2288 void
isc_mem_printallactive(FILE * file)2289 isc_mem_printallactive(FILE *file) {
2290 #if !ISC_MEM_TRACKLINES
2291 	UNUSED(file);
2292 #else
2293 	isc__mem_t *ctx;
2294 
2295 	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2296 
2297 	LOCK(&contextslock);
2298 	for (ctx = ISC_LIST_HEAD(contexts);
2299 	     ctx != NULL;
2300 	     ctx = ISC_LIST_NEXT(ctx, link)) {
2301 		fprintf(file, "context: %p\n", ctx);
2302 		print_active(ctx, file);
2303 	}
2304 	UNLOCK(&contextslock);
2305 #endif
2306 }
2307 
2308 void
isc_mem_checkdestroyed(FILE * file)2309 isc_mem_checkdestroyed(FILE *file) {
2310 #if !ISC_MEM_TRACKLINES
2311 	UNUSED(file);
2312 #endif
2313 
2314 	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2315 
2316 	LOCK(&contextslock);
2317 	if (!ISC_LIST_EMPTY(contexts))  {
2318 #if ISC_MEM_TRACKLINES
2319 		isc__mem_t *ctx;
2320 
2321 		for (ctx = ISC_LIST_HEAD(contexts);
2322 		     ctx != NULL;
2323 		     ctx = ISC_LIST_NEXT(ctx, link)) {
2324 			fprintf(file, "context: %p\n", ctx);
2325 			print_active(ctx, file);
2326 		}
2327 		fflush(file);
2328 #endif
2329 		INSIST(0);
2330 	}
2331 	UNLOCK(&contextslock);
2332 }
2333 
2334 unsigned int
isc_mem_references(isc_mem_t * ctx0)2335 isc_mem_references(isc_mem_t *ctx0) {
2336 	isc__mem_t *ctx = (isc__mem_t *)ctx0;
2337 	unsigned int references;
2338 
2339 	REQUIRE(VALID_CONTEXT(ctx));
2340 
2341 	MCTXLOCK(ctx, &ctx->lock);
2342 	references = ctx->references;
2343 	MCTXUNLOCK(ctx, &ctx->lock);
2344 
2345 	return (references);
2346 }
2347 
2348 #if defined(HAVE_LIBXML2) || defined(HAVE_JSON)
2349 typedef struct summarystat {
2350 	isc_uint64_t	total;
2351 	isc_uint64_t	inuse;
2352 	isc_uint64_t	blocksize;
2353 	isc_uint64_t	contextsize;
2354 } summarystat_t;
2355 #endif
2356 
2357 #ifdef HAVE_LIBXML2
2358 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(/*CONSTCOND*/0)
2359 static int
xml_renderctx(isc__mem_t * ctx,summarystat_t * summary,xmlTextWriterPtr writer)2360 xml_renderctx(isc__mem_t *ctx, summarystat_t *summary,
2361 	      xmlTextWriterPtr writer)
2362 {
2363 	int xmlrc;
2364 
2365 	REQUIRE(VALID_CONTEXT(ctx));
2366 
2367 	MCTXLOCK(ctx, &ctx->lock);
2368 
2369 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"));
2370 
2371 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
2372 	TRY0(xmlTextWriterWriteFormatString(writer, "%p", ctx));
2373 	TRY0(xmlTextWriterEndElement(writer)); /* id */
2374 
2375 	if (ctx->name[0] != 0) {
2376 		TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
2377 		TRY0(xmlTextWriterWriteFormatString(writer, "%s", ctx->name));
2378 		TRY0(xmlTextWriterEndElement(writer)); /* name */
2379 	}
2380 
2381 	summary->contextsize += sizeof(*ctx) +
2382 		(ctx->max_size + 1) * sizeof(struct stats) +
2383 		ctx->max_size * sizeof(element *) +
2384 		ctx->basic_table_count * sizeof(char *);
2385 #if ISC_MEM_TRACKLINES
2386 	if (ctx->debuglist != NULL) {
2387 		summary->contextsize +=
2388 			(ctx->max_size + 1) * sizeof(debuglist_t) +
2389 			ctx->debuglistcnt * sizeof(debuglink_t);
2390 	}
2391 #endif
2392 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
2393 	TRY0(xmlTextWriterWriteFormatString(writer, "%d", ctx->references));
2394 	TRY0(xmlTextWriterEndElement(writer)); /* references */
2395 
2396 	summary->total += ctx->total;
2397 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"));
2398 	TRY0(xmlTextWriterWriteFormatString(writer,
2399 					    "%" ISC_PRINT_QUADFORMAT "u",
2400 					    (isc_uint64_t)ctx->total));
2401 	TRY0(xmlTextWriterEndElement(writer)); /* total */
2402 
2403 	summary->inuse += ctx->inuse;
2404 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"));
2405 	TRY0(xmlTextWriterWriteFormatString(writer,
2406 					    "%" ISC_PRINT_QUADFORMAT "u",
2407 					    (isc_uint64_t)ctx->inuse));
2408 	TRY0(xmlTextWriterEndElement(writer)); /* inuse */
2409 
2410 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"));
2411 	TRY0(xmlTextWriterWriteFormatString(writer,
2412 					    "%" ISC_PRINT_QUADFORMAT "u",
2413 					    (isc_uint64_t)ctx->maxinuse));
2414 	TRY0(xmlTextWriterEndElement(writer)); /* maxinuse */
2415 
2416 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"));
2417 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2418 		summary->blocksize += ctx->basic_table_count *
2419 			NUM_BASIC_BLOCKS * ctx->mem_target;
2420 		TRY0(xmlTextWriterWriteFormatString(writer,
2421 					       "%" ISC_PRINT_QUADFORMAT "u",
2422 					       (isc_uint64_t)
2423 					       ctx->basic_table_count *
2424 					       NUM_BASIC_BLOCKS *
2425 					       ctx->mem_target));
2426 	} else
2427 		TRY0(xmlTextWriterWriteFormatString(writer, "%s", "-"));
2428 	TRY0(xmlTextWriterEndElement(writer)); /* blocksize */
2429 
2430 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"));
2431 	TRY0(xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt));
2432 	TRY0(xmlTextWriterEndElement(writer)); /* pools */
2433 	summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
2434 
2435 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"));
2436 	TRY0(xmlTextWriterWriteFormatString(writer,
2437 					    "%" ISC_PRINT_QUADFORMAT "u",
2438 					    (isc_uint64_t)ctx->hi_water));
2439 	TRY0(xmlTextWriterEndElement(writer)); /* hiwater */
2440 
2441 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"));
2442 	TRY0(xmlTextWriterWriteFormatString(writer,
2443 					    "%" ISC_PRINT_QUADFORMAT "u",
2444 					    (isc_uint64_t)ctx->lo_water));
2445 	TRY0(xmlTextWriterEndElement(writer)); /* lowater */
2446 
2447 	TRY0(xmlTextWriterEndElement(writer)); /* context */
2448 
2449  error:
2450 	MCTXUNLOCK(ctx, &ctx->lock);
2451 
2452 	return (xmlrc);
2453 }
2454 
2455 int
isc_mem_renderxml(xmlTextWriterPtr writer)2456 isc_mem_renderxml(xmlTextWriterPtr writer) {
2457 	isc__mem_t *ctx;
2458 	summarystat_t summary;
2459 	isc_uint64_t lost;
2460 	int xmlrc;
2461 
2462 	memset(&summary, 0, sizeof(summary));
2463 
2464 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"));
2465 
2466 	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2467 
2468 	LOCK(&contextslock);
2469 	lost = totallost;
2470 	for (ctx = ISC_LIST_HEAD(contexts);
2471 	     ctx != NULL;
2472 	     ctx = ISC_LIST_NEXT(ctx, link)) {
2473 		xmlrc = xml_renderctx(ctx, &summary, writer);
2474 		if (xmlrc < 0) {
2475 			UNLOCK(&contextslock);
2476 			goto error;
2477 		}
2478 	}
2479 	UNLOCK(&contextslock);
2480 
2481 	TRY0(xmlTextWriterEndElement(writer)); /* contexts */
2482 
2483 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"));
2484 
2485 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"));
2486 	TRY0(xmlTextWriterWriteFormatString(writer,
2487 					    "%" ISC_PRINT_QUADFORMAT "u",
2488 					    summary.total));
2489 	TRY0(xmlTextWriterEndElement(writer)); /* TotalUse */
2490 
2491 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"));
2492 	TRY0(xmlTextWriterWriteFormatString(writer,
2493 					    "%" ISC_PRINT_QUADFORMAT "u",
2494 					    summary.inuse));
2495 	TRY0(xmlTextWriterEndElement(writer)); /* InUse */
2496 
2497 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"));
2498 	TRY0(xmlTextWriterWriteFormatString(writer,
2499 					    "%" ISC_PRINT_QUADFORMAT "u",
2500 					    summary.blocksize));
2501 	TRY0(xmlTextWriterEndElement(writer)); /* BlockSize */
2502 
2503 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"));
2504 	TRY0(xmlTextWriterWriteFormatString(writer,
2505 					    "%" ISC_PRINT_QUADFORMAT "u",
2506 					    summary.contextsize));
2507 	TRY0(xmlTextWriterEndElement(writer)); /* ContextSize */
2508 
2509 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"));
2510 	TRY0(xmlTextWriterWriteFormatString(writer,
2511 					    "%" ISC_PRINT_QUADFORMAT "u",
2512 					    lost));
2513 	TRY0(xmlTextWriterEndElement(writer)); /* Lost */
2514 
2515 	TRY0(xmlTextWriterEndElement(writer)); /* summary */
2516  error:
2517 	return (xmlrc);
2518 }
2519 
2520 #endif /* HAVE_LIBXML2 */
2521 
2522 #ifdef HAVE_JSON
2523 #define CHECKMEM(m) do { \
2524 	if (m == NULL) { \
2525 		result = ISC_R_NOMEMORY;\
2526 		goto error;\
2527 	} \
2528 } while(/*CONSTCOND*/0)
2529 
2530 static isc_result_t
json_renderctx(isc__mem_t * ctx,summarystat_t * summary,json_object * array)2531 json_renderctx(isc__mem_t *ctx, summarystat_t *summary, json_object *array) {
2532 	isc_result_t result = ISC_R_FAILURE;
2533 	json_object *ctxobj, *obj;
2534 	char buf[1024];
2535 
2536 	REQUIRE(VALID_CONTEXT(ctx));
2537 	REQUIRE(summary != NULL);
2538 	REQUIRE(array != NULL);
2539 
2540 	MCTXLOCK(ctx, &ctx->lock);
2541 
2542 	summary->contextsize += sizeof(*ctx) +
2543 		(ctx->max_size + 1) * sizeof(struct stats) +
2544 		ctx->max_size * sizeof(element *) +
2545 		ctx->basic_table_count * sizeof(char *);
2546 	summary->total += ctx->total;
2547 	summary->inuse += ctx->inuse;
2548 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
2549 		summary->blocksize += ctx->basic_table_count *
2550 			NUM_BASIC_BLOCKS * ctx->mem_target;
2551 #if ISC_MEM_TRACKLINES
2552 	if (ctx->debuglist != NULL) {
2553 		summary->contextsize +=
2554 			(ctx->max_size + 1) * sizeof(debuglist_t) +
2555 			ctx->debuglistcnt * sizeof(debuglink_t);
2556 	}
2557 #endif
2558 
2559 	ctxobj = json_object_new_object();
2560 	CHECKMEM(ctxobj);
2561 
2562 	sprintf(buf, "%p", ctx);
2563 	obj = json_object_new_string(buf);
2564 	CHECKMEM(obj);
2565 	json_object_object_add(ctxobj, "id", obj);
2566 
2567 	if (ctx->name[0] != 0) {
2568 		obj = json_object_new_string(ctx->name);
2569 		CHECKMEM(obj);
2570 		json_object_object_add(ctxobj, "name", obj);
2571 	}
2572 
2573 	obj = json_object_new_int64(ctx->references);
2574 	CHECKMEM(obj);
2575 	json_object_object_add(ctxobj, "references", obj);
2576 
2577 	obj = json_object_new_int64(ctx->total);
2578 	CHECKMEM(obj);
2579 	json_object_object_add(ctxobj, "total", obj);
2580 
2581 	obj = json_object_new_int64(ctx->inuse);
2582 	CHECKMEM(obj);
2583 	json_object_object_add(ctxobj, "inuse", obj);
2584 
2585 	obj = json_object_new_int64(ctx->maxinuse);
2586 	CHECKMEM(obj);
2587 	json_object_object_add(ctxobj, "maxinuse", obj);
2588 
2589 	if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
2590 		isc_uint64_t blocksize;
2591 		blocksize = ctx->basic_table_count * NUM_BASIC_BLOCKS *
2592 			ctx->mem_target;
2593 		obj = json_object_new_int64(blocksize);
2594 		CHECKMEM(obj);
2595 		json_object_object_add(ctxobj, "blocksize", obj);
2596 	}
2597 
2598 	obj = json_object_new_int64(ctx->poolcnt);
2599 	CHECKMEM(obj);
2600 	json_object_object_add(ctxobj, "pools", obj);
2601 
2602 	obj = json_object_new_int64(ctx->hi_water);
2603 	CHECKMEM(obj);
2604 	json_object_object_add(ctxobj, "hiwater", obj);
2605 
2606 	obj = json_object_new_int64(ctx->lo_water);
2607 	CHECKMEM(obj);
2608 	json_object_object_add(ctxobj, "lowater", obj);
2609 
2610 	MCTXUNLOCK(ctx, &ctx->lock);
2611 	json_object_array_add(array, ctxobj);
2612 	return (ISC_R_SUCCESS);
2613 
2614  error:
2615 	MCTXUNLOCK(ctx, &ctx->lock);
2616 	if (ctxobj != NULL)
2617 		json_object_put(ctxobj);
2618 	return (result);
2619 }
2620 
2621 isc_result_t
isc_mem_renderjson(json_object * memobj)2622 isc_mem_renderjson(json_object *memobj) {
2623 	isc_result_t result = ISC_R_SUCCESS;
2624 	isc__mem_t *ctx;
2625 	summarystat_t summary;
2626 	isc_uint64_t lost;
2627 	json_object *ctxarray, *obj;
2628 
2629 	memset(&summary, 0, sizeof(summary));
2630 	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2631 
2632 	ctxarray = json_object_new_array();
2633 	CHECKMEM(ctxarray);
2634 
2635 	LOCK(&contextslock);
2636 	lost = totallost;
2637 	for (ctx = ISC_LIST_HEAD(contexts);
2638 	     ctx != NULL;
2639 	     ctx = ISC_LIST_NEXT(ctx, link)) {
2640 		result = json_renderctx(ctx, &summary, ctxarray);
2641 		if (result != ISC_R_SUCCESS) {
2642 			UNLOCK(&contextslock);
2643 			goto error;
2644 		}
2645 	}
2646 	UNLOCK(&contextslock);
2647 
2648 	obj = json_object_new_int64(summary.total);
2649 	CHECKMEM(obj);
2650 	json_object_object_add(memobj, "TotalUse", obj);
2651 
2652 	obj = json_object_new_int64(summary.inuse);
2653 	CHECKMEM(obj);
2654 	json_object_object_add(memobj, "InUse", obj);
2655 
2656 	obj = json_object_new_int64(summary.blocksize);
2657 	CHECKMEM(obj);
2658 	json_object_object_add(memobj, "BlockSize", obj);
2659 
2660 	obj = json_object_new_int64(summary.contextsize);
2661 	CHECKMEM(obj);
2662 	json_object_object_add(memobj, "ContextSize", obj);
2663 
2664 	obj = json_object_new_int64(lost);
2665 	CHECKMEM(obj);
2666 	json_object_object_add(memobj, "Lost", obj);
2667 
2668 	json_object_object_add(memobj, "contexts", ctxarray);
2669 	return (ISC_R_SUCCESS);
2670 
2671  error:
2672 	if (ctxarray != NULL)
2673 		json_object_put(ctxarray);
2674 	return (result);
2675 }
2676 #endif /* HAVE_JSON */
2677 
2678 static isc_memcreatefunc_t mem_createfunc = NULL;
2679 
2680 isc_result_t
isc_mem_register(isc_memcreatefunc_t createfunc)2681 isc_mem_register(isc_memcreatefunc_t createfunc) {
2682 	isc_result_t result = ISC_R_SUCCESS;
2683 
2684 	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
2685 
2686 	LOCK(&createlock);
2687 	if (mem_createfunc == NULL)
2688 		mem_createfunc = createfunc;
2689 	else
2690 		result = ISC_R_EXISTS;
2691 	UNLOCK(&createlock);
2692 
2693 	return (result);
2694 }
2695 
2696 
2697 isc_result_t
isc__mem_create2(size_t init_max_size,size_t target_size,isc_mem_t ** mctxp,unsigned int flags)2698 isc__mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **mctxp,
2699 		 unsigned int flags)
2700 {
2701 	isc_result_t result;
2702 
2703 	LOCK(&createlock);
2704 
2705 	REQUIRE(mem_createfunc != NULL);
2706 	result = (*mem_createfunc)(init_max_size, target_size, mctxp, flags);
2707 
2708 	UNLOCK(&createlock);
2709 
2710 	return (result);
2711 }
2712 
2713 isc_result_t
isc_mem_create(size_t init_max_size,size_t target_size,isc_mem_t ** mctxp)2714 isc_mem_create(size_t init_max_size, size_t target_size, isc_mem_t **mctxp) {
2715 	isc_result_t result;
2716 
2717 	if (isc_bind9)
2718 		return (isc_mem_createx2(init_max_size, target_size,
2719 					 default_memalloc, default_memfree,
2720 					 NULL, mctxp, ISC_MEMFLAG_DEFAULT));
2721 	LOCK(&createlock);
2722 
2723 	REQUIRE(mem_createfunc != NULL);
2724 	result = (*mem_createfunc)(init_max_size, target_size, mctxp,
2725 				   ISC_MEMFLAG_DEFAULT);
2726 
2727 	UNLOCK(&createlock);
2728 
2729 	return (result);
2730 }
2731 
2732 isc_result_t
isc_mem_create2(size_t init_max_size,size_t target_size,isc_mem_t ** mctxp,unsigned int flags)2733 isc_mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **mctxp,
2734 		 unsigned int flags)
2735 {
2736 	if (isc_bind9)
2737 		return (isc_mem_createx2(init_max_size, target_size,
2738 					 default_memalloc, default_memfree,
2739 					 NULL, mctxp, flags));
2740 
2741 	return (isc_mem_createx2(init_max_size, target_size,
2742 				 default_memalloc, default_memfree,
2743 				 NULL, mctxp, flags));
2744 }
2745 
2746 void
isc_mem_attach(isc_mem_t * source,isc_mem_t ** targetp)2747 isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) {
2748 	REQUIRE(ISCAPI_MCTX_VALID(source));
2749 	REQUIRE(targetp != NULL && *targetp == NULL);
2750 
2751 	if (isc_bind9)
2752 		isc__mem_attach(source, targetp);
2753 	else
2754 		source->methods->attach(source, targetp);
2755 
2756 	ENSURE(*targetp == source);
2757 }
2758 
2759 void
isc_mem_detach(isc_mem_t ** mctxp)2760 isc_mem_detach(isc_mem_t **mctxp) {
2761 	REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
2762 
2763 	if (isc_bind9)
2764 		isc__mem_detach(mctxp);
2765 	else
2766 		(*mctxp)->methods->detach(mctxp);
2767 
2768 	ENSURE(*mctxp == NULL);
2769 }
2770 
2771 void
isc_mem_destroy(isc_mem_t ** mctxp)2772 isc_mem_destroy(isc_mem_t **mctxp) {
2773 	REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
2774 
2775 	if (isc_bind9)
2776 		isc__mem_destroy(mctxp);
2777 	else
2778 		(*mctxp)->methods->destroy(mctxp);
2779 
2780 	ENSURE(*mctxp == NULL);
2781 }
2782 
2783 void
isc_mem_setdestroycheck(isc_mem_t * mctx,isc_boolean_t flag)2784 isc_mem_setdestroycheck(isc_mem_t *mctx, isc_boolean_t flag) {
2785 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2786 
2787 	mctx->methods->setdestroycheck(mctx, flag);
2788 }
2789 
2790 void
isc_mem_setwater(isc_mem_t * ctx,isc_mem_water_t water,void * water_arg,size_t hiwater,size_t lowater)2791 isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
2792 		 size_t hiwater, size_t lowater)
2793 {
2794 	REQUIRE(ISCAPI_MCTX_VALID(ctx));
2795 
2796 	if (isc_bind9)
2797 		isc__mem_setwater(ctx, water, water_arg, hiwater, lowater);
2798 	else
2799 		ctx->methods->setwater(ctx, water, water_arg, hiwater, lowater);
2800 }
2801 
2802 void
isc_mem_waterack(isc_mem_t * ctx,int flag)2803 isc_mem_waterack(isc_mem_t *ctx, int flag) {
2804 	REQUIRE(ISCAPI_MCTX_VALID(ctx));
2805 
2806 	if (isc_bind9)
2807 		isc__mem_waterack(ctx, flag);
2808 	else
2809 		ctx->methods->waterack(ctx, flag);
2810 }
2811 
2812 size_t
isc_mem_inuse(isc_mem_t * mctx)2813 isc_mem_inuse(isc_mem_t *mctx) {
2814 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2815 
2816 	if (isc_bind9)
2817 		return (isc__mem_inuse(mctx));
2818 
2819 	return (mctx->methods->inuse(mctx));
2820 }
2821 
2822 size_t
isc_mem_maxinuse(isc_mem_t * mctx)2823 isc_mem_maxinuse(isc_mem_t *mctx) {
2824 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2825 
2826 	if (isc_bind9)
2827 		return (isc__mem_maxinuse(mctx));
2828 
2829 	return (mctx->methods->maxinuse(mctx));
2830 }
2831 
2832 size_t
isc_mem_total(isc_mem_t * mctx)2833 isc_mem_total(isc_mem_t *mctx) {
2834 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2835 
2836 	if (isc_bind9)
2837 		return (isc__mem_total(mctx));
2838 
2839 	return (mctx->methods->total(mctx));
2840 }
2841 
2842 isc_boolean_t
isc_mem_isovermem(isc_mem_t * mctx)2843 isc_mem_isovermem(isc_mem_t *mctx) {
2844 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2845 
2846 	if (isc_bind9)
2847 		return (isc__mem_isovermem(mctx));
2848 
2849 	return (mctx->methods->isovermem(mctx));
2850 }
2851 
2852 
2853 isc_result_t
isc_mempool_create(isc_mem_t * mctx,size_t size,isc_mempool_t ** mpctxp)2854 isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) {
2855 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2856 
2857 	return (mctx->methods->mpcreate(mctx, size, mpctxp));
2858 }
2859 
2860 void
isc_mempool_destroy(isc_mempool_t ** mpctxp)2861 isc_mempool_destroy(isc_mempool_t **mpctxp) {
2862 	REQUIRE(mpctxp != NULL && ISCAPI_MPOOL_VALID(*mpctxp));
2863 
2864 	if (isc_bind9)
2865 		isc__mempool_destroy(mpctxp);
2866 	else
2867 		(*mpctxp)->methods->destroy(mpctxp);
2868 
2869 	ENSURE(*mpctxp == NULL);
2870 }
2871 
2872 unsigned int
isc_mempool_getallocated(isc_mempool_t * mpctx)2873 isc_mempool_getallocated(isc_mempool_t *mpctx) {
2874 	REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2875 
2876 	if (isc_bind9)
2877 		return (isc__mempool_getallocated(mpctx));
2878 
2879 	return (mpctx->methods->getallocated(mpctx));
2880 }
2881 
2882 void
isc_mempool_setmaxalloc(isc_mempool_t * mpctx,unsigned int limit)2883 isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) {
2884 	REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2885 
2886 	if (isc_bind9)
2887 		isc__mempool_setmaxalloc(mpctx, limit);
2888 	else
2889 		mpctx->methods->setmaxalloc(mpctx, limit);
2890 }
2891 
2892 void
isc_mempool_setfreemax(isc_mempool_t * mpctx,unsigned int limit)2893 isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) {
2894 	REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2895 
2896 	if (isc_bind9)
2897 		isc__mempool_setfreemax(mpctx, limit);
2898 	else
2899 		mpctx->methods->setfreemax(mpctx, limit);
2900 }
2901 
2902 void
isc_mempool_setname(isc_mempool_t * mpctx,const char * name)2903 isc_mempool_setname(isc_mempool_t *mpctx, const char *name) {
2904 	REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2905 
2906 	if (isc_bind9)
2907 		isc__mempool_setname(mpctx, name);
2908 	else
2909 		mpctx->methods->setname(mpctx, name);
2910 }
2911 
2912 void
isc_mempool_associatelock(isc_mempool_t * mpctx,isc_mutex_t * lock)2913 isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) {
2914 	REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2915 
2916 	if (isc_bind9)
2917 		isc__mempool_associatelock(mpctx, lock);
2918 	else
2919 		mpctx->methods->associatelock(mpctx, lock);
2920 }
2921 
2922 void
isc_mempool_setfillcount(isc_mempool_t * mpctx,unsigned int limit)2923 isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) {
2924 	REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
2925 
2926 	if (isc_bind9)
2927 		isc__mempool_setfillcount(mpctx, limit);
2928 	else
2929 		mpctx->methods->setfillcount(mpctx, limit);
2930 }
2931 
2932 void *
isc__mem_get(isc_mem_t * mctx,size_t size FLARG)2933 isc__mem_get(isc_mem_t *mctx, size_t size FLARG) {
2934 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2935 
2936 	if (isc_bind9)
2937 		return (isc___mem_get(mctx, size FLARG_PASS));
2938 
2939 	return (mctx->methods->memget(mctx, size FLARG_PASS));
2940 
2941 }
2942 
2943 void
isc__mem_put(isc_mem_t * mctx,void * ptr,size_t size FLARG)2944 isc__mem_put(isc_mem_t *mctx, void *ptr, size_t size FLARG) {
2945 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2946 
2947 	if (isc_bind9)
2948 		isc___mem_put(mctx, ptr, size FLARG_PASS);
2949 	else
2950 		mctx->methods->memput(mctx, ptr, size FLARG_PASS);
2951 }
2952 
2953 void
isc__mem_putanddetach(isc_mem_t ** mctxp,void * ptr,size_t size FLARG)2954 isc__mem_putanddetach(isc_mem_t **mctxp, void *ptr, size_t size FLARG) {
2955 	REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp));
2956 
2957 	if (isc_bind9)
2958 		isc___mem_putanddetach(mctxp, ptr, size FLARG_PASS);
2959 	else
2960 		(*mctxp)->methods->memputanddetach(mctxp, ptr, size FLARG_PASS);
2961 
2962 	/*
2963 	 * XXX: We cannot always ensure *mctxp == NULL here
2964 	 * (see lib/isc/mem.c).
2965 	 */
2966 }
2967 
2968 void *
isc__mem_allocate(isc_mem_t * mctx,size_t size FLARG)2969 isc__mem_allocate(isc_mem_t *mctx, size_t size FLARG) {
2970 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2971 
2972 	if (isc_bind9)
2973 		return (isc___mem_allocate(mctx, size FLARG_PASS));
2974 
2975 	return (mctx->methods->memallocate(mctx, size FLARG_PASS));
2976 }
2977 
2978 void *
isc__mem_reallocate(isc_mem_t * mctx,void * ptr,size_t size FLARG)2979 isc__mem_reallocate(isc_mem_t *mctx, void *ptr, size_t size FLARG) {
2980 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2981 
2982 	if (isc_bind9)
2983 		return (isc___mem_reallocate(mctx, ptr, size FLARG_PASS));
2984 
2985 	return (mctx->methods->memreallocate(mctx, ptr, size FLARG_PASS));
2986 }
2987 
2988 char *
isc__mem_strdup(isc_mem_t * mctx,const char * s FLARG)2989 isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
2990 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
2991 
2992 	if (isc_bind9)
2993 		return (isc___mem_strdup(mctx, s FLARG_PASS));
2994 
2995 	return (mctx->methods->memstrdup(mctx, s FLARG_PASS));
2996 }
2997 
2998 void
isc__mem_free(isc_mem_t * mctx,void * ptr FLARG)2999 isc__mem_free(isc_mem_t *mctx, void *ptr FLARG) {
3000 	REQUIRE(ISCAPI_MCTX_VALID(mctx));
3001 
3002 	if (isc_bind9)
3003 		isc___mem_free(mctx, ptr FLARG_PASS);
3004 	else
3005 		mctx->methods->memfree(mctx, ptr FLARG_PASS);
3006 }
3007 
3008 void *
isc__mempool_get(isc_mempool_t * mpctx FLARG)3009 isc__mempool_get(isc_mempool_t *mpctx FLARG) {
3010 	REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
3011 
3012 	if (isc_bind9)
3013 		return (isc___mempool_get(mpctx FLARG_PASS));
3014 
3015 	return (mpctx->methods->get(mpctx FLARG_PASS));
3016 }
3017 
3018 void
isc__mempool_put(isc_mempool_t * mpctx,void * mem FLARG)3019 isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) {
3020 	REQUIRE(ISCAPI_MPOOL_VALID(mpctx));
3021 
3022 	if (isc_bind9)
3023 		isc___mempool_put(mpctx, mem FLARG_PASS);
3024 	else
3025 		mpctx->methods->put(mpctx, mem FLARG_PASS);
3026 }
3027