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