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