"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/isc/mem.c" (7 Sep 2020, 71182 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mem.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.17.3_vs_9.17.4.

    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 http://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
  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
  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
  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
  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
  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
  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 *
  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
  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
  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 *
  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
  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
  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
  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 *
  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 *
  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
  913 default_memfree(void *arg, void *ptr) {
  914     UNUSED(arg);
  915     free(ptr);
  916 }
  917 
  918 static 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
  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
  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
 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
 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
 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
 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
 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
 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 *
 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
 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
 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
 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
 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 *
 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 *
 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 *
 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
 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 *
 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
 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
 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
 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
 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
 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
 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
 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 bool
 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
 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 *
 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 *
 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
 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
 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
 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
 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 *
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 2339 isc__mem_register(void) {
 2340     return (isc_mem_register(isc_mem_create2));
 2341 }
 2342 
 2343 void
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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 *
 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
 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
 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 *
 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 *
 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 *
 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
 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 *
 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
 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 }