1 /* $NetBSD: mem.h,v 1.1 2024/02/18 20:57:53 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #ifndef ISC_MEM_H 17 #define ISC_MEM_H 1 18 19 /*! \file isc/mem.h */ 20 21 #include <stdbool.h> 22 #include <stdio.h> 23 24 #include <isc/lang.h> 25 #include <isc/mutex.h> 26 #include <isc/platform.h> 27 #include <isc/types.h> 28 #include <isc/util.h> 29 30 ISC_LANG_BEGINDECLS 31 32 #define ISC_MEM_LOWATER 0 33 #define ISC_MEM_HIWATER 1 34 typedef void (*isc_mem_water_t)(void *, int); 35 36 /*% 37 * Define ISC_MEM_TRACKLINES=1 to turn on detailed tracing of memory 38 * allocation and freeing by file and line number. 39 */ 40 #ifndef ISC_MEM_TRACKLINES 41 #define ISC_MEM_TRACKLINES 1 42 #endif /* ifndef ISC_MEM_TRACKLINES */ 43 44 /*% 45 * Define ISC_MEM_CHECKOVERRUN=1 to turn on checks for using memory outside 46 * the requested space. This will increase the size of each allocation. 47 * 48 * If we are performing a Coverity static analysis then ISC_MEM_CHECKOVERRUN 49 * can hide bugs that would otherwise discovered so force to zero. 50 */ 51 #ifdef __COVERITY__ 52 #undef ISC_MEM_CHECKOVERRUN 53 #define ISC_MEM_CHECKOVERRUN 0 54 #endif /* ifdef __COVERITY__ */ 55 #ifndef ISC_MEM_CHECKOVERRUN 56 #define ISC_MEM_CHECKOVERRUN 1 57 #endif /* ifndef ISC_MEM_CHECKOVERRUN */ 58 59 /*% 60 * Define ISC_MEMPOOL_NAMES=1 to make memory pools store a symbolic 61 * name so that the leaking pool can be more readily identified in 62 * case of a memory leak. 63 */ 64 #ifndef ISC_MEMPOOL_NAMES 65 #define ISC_MEMPOOL_NAMES 1 66 #endif /* ifndef ISC_MEMPOOL_NAMES */ 67 68 LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_debugging; 69 LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_defaultflags; 70 71 /*@{*/ 72 #define ISC_MEM_DEBUGTRACE 0x00000001U 73 #define ISC_MEM_DEBUGRECORD 0x00000002U 74 #define ISC_MEM_DEBUGUSAGE 0x00000004U 75 #define ISC_MEM_DEBUGSIZE 0x00000008U 76 #define ISC_MEM_DEBUGCTX 0x00000010U 77 #define ISC_MEM_DEBUGALL 0x0000001FU 78 /*!< 79 * The variable isc_mem_debugging holds a set of flags for 80 * turning certain memory debugging options on or off at 81 * runtime. It is initialized to the value ISC_MEM_DEGBUGGING, 82 * which is 0 by default but may be overridden at compile time. 83 * The following flags can be specified: 84 * 85 * \li #ISC_MEM_DEBUGTRACE 86 * Log each allocation and free to isc_lctx. 87 * 88 * \li #ISC_MEM_DEBUGRECORD 89 * Remember each allocation, and match them up on free. 90 * Crash if a free doesn't match an allocation. 91 * 92 * \li #ISC_MEM_DEBUGUSAGE 93 * If a hi_water mark is set, print the maximum inuse memory 94 * every time it is raised once it exceeds the hi_water mark. 95 * 96 * \li #ISC_MEM_DEBUGSIZE 97 * Check the size argument being passed to isc_mem_put() matches 98 * that passed to isc_mem_get(). 99 * 100 * \li #ISC_MEM_DEBUGCTX 101 * Check the mctx argument being passed to isc_mem_put() matches 102 * that passed to isc_mem_get(). 103 */ 104 /*@}*/ 105 106 #if ISC_MEM_TRACKLINES 107 #define _ISC_MEM_FILELINE , __FILE__, __LINE__ 108 #define _ISC_MEM_FLARG , const char *, unsigned int 109 #else /* if ISC_MEM_TRACKLINES */ 110 #define _ISC_MEM_FILELINE 111 #define _ISC_MEM_FLARG 112 #endif /* if ISC_MEM_TRACKLINES */ 113 114 /*! 115 * Define ISC_MEM_USE_INTERNAL_MALLOC=1 to use the internal malloc() 116 * implementation in preference to the system one. The internal malloc() 117 * is very space-efficient, and quite fast on uniprocessor systems. It 118 * performs poorly on multiprocessor machines. 119 * JT: we can overcome the performance issue on multiprocessor machines 120 * by carefully separating memory contexts. 121 */ 122 123 #if !defined(ISC_MEM_USE_INTERNAL_MALLOC) && !__SANITIZE_ADDRESS__ 124 #define ISC_MEM_USE_INTERNAL_MALLOC 0 125 #endif /* ifndef ISC_MEM_USE_INTERNAL_MALLOC */ 126 127 /* 128 * Flags for isc_mem_create() calls. 129 */ 130 #define ISC_MEMFLAG_RESERVED 0x00000001 /* reserved, obsoleted, don't use */ 131 #define ISC_MEMFLAG_INTERNAL 0x00000002 /* use internal malloc */ 132 #define ISC_MEMFLAG_FILL \ 133 0x00000004 /* fill with pattern after alloc and frees */ 134 135 /*% 136 * Define ISC_MEM_DEFAULTFILL=1 to turn filling the memory with pattern 137 * after alloc and free. 138 */ 139 #if !ISC_MEM_USE_INTERNAL_MALLOC 140 141 #if ISC_MEM_DEFAULTFILL 142 #define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_FILL 143 #else /* if ISC_MEM_DEFAULTFILL */ 144 #define ISC_MEMFLAG_DEFAULT 0 145 #endif /* if ISC_MEM_DEFAULTFILL */ 146 147 #else /* if !ISC_MEM_USE_INTERNAL_MALLOC */ 148 149 #if ISC_MEM_DEFAULTFILL 150 #define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_INTERNAL | ISC_MEMFLAG_FILL 151 #else /* if ISC_MEM_DEFAULTFILL */ 152 #define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_INTERNAL 153 #endif /* if ISC_MEM_DEFAULTFILL */ 154 155 #endif /* if !ISC_MEM_USE_INTERNAL_MALLOC */ 156 157 /*% 158 * isc_mem_putanddetach() is a convenience function for use where you 159 * have a structure with an attached memory context. 160 * 161 * Given: 162 * 163 * \code 164 * struct { 165 * ... 166 * isc_mem_t *mctx; 167 * ... 168 * } *ptr; 169 * 170 * isc_mem_t *mctx; 171 * 172 * isc_mem_putanddetach(&ptr->mctx, ptr, sizeof(*ptr)); 173 * \endcode 174 * 175 * is the equivalent of: 176 * 177 * \code 178 * mctx = NULL; 179 * isc_mem_attach(ptr->mctx, &mctx); 180 * isc_mem_detach(&ptr->mctx); 181 * isc_mem_put(mctx, ptr, sizeof(*ptr)); 182 * isc_mem_detach(&mctx); 183 * \endcode 184 */ 185 186 /*% memory and memory pool methods */ 187 typedef struct isc_memmethods { 188 void *(*memget)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG); 189 void (*memput)(isc_mem_t *mctx, void *ptr, size_t size _ISC_MEM_FLARG); 190 void (*memputanddetach)(isc_mem_t **mctxp, void *ptr, 191 size_t size _ISC_MEM_FLARG); 192 void *(*memallocate)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG); 193 void *(*memreallocate)(isc_mem_t *mctx, void *ptr, 194 size_t size _ISC_MEM_FLARG); 195 char *(*memstrdup)(isc_mem_t *mctx, const char *s _ISC_MEM_FLARG); 196 char *(*memstrndup)(isc_mem_t *mctx, const char *s, 197 size_t size _ISC_MEM_FLARG); 198 void (*memfree)(isc_mem_t *mctx, void *ptr _ISC_MEM_FLARG); 199 } isc_memmethods_t; 200 201 /*% 202 * This structure is actually just the common prefix of a memory context 203 * implementation's version of an isc_mem_t. 204 * \brief 205 * Direct use of this structure by clients is forbidden. mctx implementations 206 * may change the structure. 'magic' must be ISCAPI_MCTX_MAGIC for any of the 207 * isc_mem_ routines to work. mctx implementations must maintain all mctx 208 * invariants. 209 */ 210 struct isc_mem { 211 unsigned int impmagic; 212 unsigned int magic; 213 isc_memmethods_t *methods; 214 }; 215 216 #define ISCAPI_MCTX_MAGIC ISC_MAGIC('A', 'm', 'c', 'x') 217 #define ISCAPI_MCTX_VALID(m) ((m) != NULL && (m)->magic == ISCAPI_MCTX_MAGIC) 218 219 /*% 220 * This is the common prefix of a memory pool context. The same note as 221 * that for the mem structure applies. 222 */ 223 struct isc_mempool { 224 unsigned int impmagic; 225 unsigned int magic; 226 }; 227 228 #define ISCAPI_MPOOL_MAGIC ISC_MAGIC('A', 'm', 'p', 'l') 229 #define ISCAPI_MPOOL_VALID(mp) \ 230 ((mp) != NULL && (mp)->magic == ISCAPI_MPOOL_MAGIC) 231 232 /*% 233 * These functions are actually implemented in isc__mem_<function> 234 * (two underscores). The single-underscore macros are used to pass 235 * __FILE__ and __LINE__, and in the case of the put functions, to 236 * set the pointer being freed to NULL in the calling function. 237 * 238 * Many of these functions have a further isc___mem_<function> 239 * (three underscores) implementation, which is called indirectly 240 * via the isc_memmethods structure in the mctx so that dynamically 241 * loaded modules can use them even if named is statically linked. 242 */ 243 244 #define ISCMEMFUNC(sfx) isc__mem_##sfx 245 #define ISCMEMPOOLFUNC(sfx) isc__mempool_##sfx 246 247 #define isc_mem_get(c, s) ISCMEMFUNC(get)((c), (s)_ISC_MEM_FILELINE) 248 #define isc_mem_allocate(c, s) ISCMEMFUNC(allocate)((c), (s)_ISC_MEM_FILELINE) 249 #define isc_mem_reallocate(c, p, s) \ 250 ISCMEMFUNC(reallocate)((c), (p), (s)_ISC_MEM_FILELINE) 251 #define isc_mem_strdup(c, p) ISCMEMFUNC(strdup)((c), (p)_ISC_MEM_FILELINE) 252 #define isc_mem_strndup(c, p, s) \ 253 ISCMEMFUNC(strndup)((c), (p), (s)_ISC_MEM_FILELINE) 254 #define isc_mempool_get(c) ISCMEMPOOLFUNC(get)((c)_ISC_MEM_FILELINE) 255 256 #define isc_mem_put(c, p, s) \ 257 do { \ 258 ISCMEMFUNC(put)((c), (p), (s)_ISC_MEM_FILELINE); \ 259 (p) = NULL; \ 260 } while (0) 261 #define isc_mem_putanddetach(c, p, s) \ 262 do { \ 263 ISCMEMFUNC(putanddetach)((c), (p), (s)_ISC_MEM_FILELINE); \ 264 (p) = NULL; \ 265 } while (0) 266 #define isc_mem_free(c, p) \ 267 do { \ 268 ISCMEMFUNC(free)((c), (p)_ISC_MEM_FILELINE); \ 269 (p) = NULL; \ 270 } while (0) 271 #define isc_mempool_put(c, p) \ 272 do { \ 273 ISCMEMPOOLFUNC(put)((c), (p)_ISC_MEM_FILELINE); \ 274 (p) = NULL; \ 275 } while (0) 276 277 /*@{*/ 278 void 279 isc_mem_create(isc_mem_t **mctxp); 280 281 /*!< 282 * \brief Create a memory context. 283 * 284 * Requires: 285 * mctxp != NULL && *mctxp == NULL */ 286 /*@}*/ 287 288 /*@{*/ 289 void 290 isc_mem_attach(isc_mem_t *, isc_mem_t **); 291 void 292 isc_mem_detach(isc_mem_t **); 293 /*!< 294 * \brief Attach to / detach from a memory context. 295 * 296 * This is intended for applications that use multiple memory contexts 297 * in such a way that it is not obvious when the last allocations from 298 * a given context has been freed and destroying the context is safe. 299 * 300 * Most applications do not need to call these functions as they can 301 * simply create a single memory context at the beginning of main() 302 * and destroy it at the end of main(), thereby guaranteeing that it 303 * is not destroyed while there are outstanding allocations. 304 */ 305 /*@}*/ 306 307 void 308 isc_mem_destroy(isc_mem_t **); 309 /*%< 310 * Destroy a memory context. 311 */ 312 313 void 314 isc_mem_stats(isc_mem_t *mctx, FILE *out); 315 /*%< 316 * Print memory usage statistics for 'mctx' on the stream 'out'. 317 */ 318 319 void 320 isc_mem_setdestroycheck(isc_mem_t *mctx, bool on); 321 /*%< 322 * If 'on' is true, 'mctx' will check for memory leaks when 323 * destroyed and abort the program if any are present. 324 */ 325 326 size_t 327 isc_mem_inuse(isc_mem_t *mctx); 328 /*%< 329 * Get an estimate of the amount of memory in use in 'mctx', in bytes. 330 * This includes quantization overhead, but does not include memory 331 * allocated from the system but not yet used. 332 */ 333 334 size_t 335 isc_mem_maxinuse(isc_mem_t *mctx); 336 /*%< 337 * Get an estimate of the largest amount of memory that has been in 338 * use in 'mctx' at any time. 339 */ 340 341 size_t 342 isc_mem_total(isc_mem_t *mctx); 343 /*%< 344 * Get the total amount of memory in 'mctx', in bytes, including memory 345 * not yet used. 346 */ 347 348 bool 349 isc_mem_isovermem(isc_mem_t *mctx); 350 /*%< 351 * Return true iff the memory context is in "over memory" state, i.e., 352 * a hiwater mark has been set and the used amount of memory has exceeds 353 * the mark. 354 */ 355 356 void 357 isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg, 358 size_t hiwater, size_t lowater); 359 /*%< 360 * Set high and low water marks for this memory context. 361 * 362 * When the memory usage of 'mctx' exceeds 'hiwater', 363 * '(water)(water_arg, #ISC_MEM_HIWATER)' will be called. 'water' needs to 364 * call isc_mem_waterack() with #ISC_MEM_HIWATER to acknowledge the state 365 * change. 'water' may be called multiple times. 366 * 367 * When the usage drops below 'lowater', 'water' will again be called, this 368 * time with #ISC_MEM_LOWATER. 'water' need to calls isc_mem_waterack() with 369 * #ISC_MEM_LOWATER to acknowledge the change. 370 * 371 * static void 372 * water(void *arg, int mark) { 373 * struct foo *foo = arg; 374 * 375 * LOCK(&foo->marklock); 376 * if (foo->mark != mark) { 377 * foo->mark = mark; 378 * .... 379 * isc_mem_waterack(foo->mctx, mark); 380 * } 381 * UNLOCK(&foo->marklock); 382 * } 383 * 384 * If 'water' is NULL then 'water_arg', 'hi_water' and 'lo_water' are 385 * ignored and the state is reset. 386 * 387 * Requires: 388 * 389 * 'water' is not NULL. 390 * hi_water >= lo_water 391 */ 392 393 void 394 isc_mem_waterack(isc_mem_t *ctx, int mark); 395 /*%< 396 * Called to acknowledge changes in signaled by calls to 'water'. 397 */ 398 399 void 400 isc_mem_checkdestroyed(FILE *file); 401 /*%< 402 * Check that all memory contexts have been destroyed. 403 * Prints out those that have not been. 404 * Fatally fails if there are still active contexts. 405 */ 406 407 unsigned int 408 isc_mem_references(isc_mem_t *ctx); 409 /*%< 410 * Return the current reference count. 411 */ 412 413 void 414 isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag); 415 /*%< 416 * Name 'ctx'. 417 * 418 * Notes: 419 * 420 *\li Only the first 15 characters of 'name' will be copied. 421 * 422 *\li 'tag' is for debugging purposes only. 423 * 424 * Requires: 425 * 426 *\li 'ctx' is a valid ctx. 427 */ 428 429 const char * 430 isc_mem_getname(isc_mem_t *ctx); 431 /*%< 432 * Get the name of 'ctx', as previously set using isc_mem_setname(). 433 * 434 * Requires: 435 *\li 'ctx' is a valid ctx. 436 * 437 * Returns: 438 *\li A non-NULL pointer to a null-terminated string. 439 * If the ctx has not been named, the string is 440 * empty. 441 */ 442 443 void * 444 isc_mem_gettag(isc_mem_t *ctx); 445 /*%< 446 * Get the tag value for 'task', as previously set using isc_mem_setname(). 447 * 448 * Requires: 449 *\li 'ctx' is a valid ctx. 450 * 451 * Notes: 452 *\li This function is for debugging purposes only. 453 * 454 * Requires: 455 *\li 'ctx' is a valid task. 456 */ 457 458 #ifdef HAVE_LIBXML2 459 int 460 isc_mem_renderxml(void *writer0); 461 /*%< 462 * Render all contexts' statistics and status in XML for writer. 463 */ 464 #endif /* HAVE_LIBXML2 */ 465 466 #ifdef HAVE_JSON_C 467 isc_result_t 468 isc_mem_renderjson(void *memobj0); 469 /*%< 470 * Render all contexts' statistics and status in JSON. 471 */ 472 #endif /* HAVE_JSON_C */ 473 474 /* 475 * Memory pools 476 */ 477 478 void 479 isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp); 480 /*%< 481 * Create a memory pool. 482 * 483 * Requires: 484 *\li mctx is a valid memory context. 485 *\li size > 0 486 *\li mpctxp != NULL and *mpctxp == NULL 487 * 488 * Defaults: 489 *\li maxalloc = UINT_MAX 490 *\li freemax = 1 491 *\li fillcount = 1 492 * 493 * Returns: 494 *\li #ISC_R_NOMEMORY -- not enough memory to create pool 495 *\li #ISC_R_SUCCESS -- all is well. 496 */ 497 498 void 499 isc_mempool_destroy(isc_mempool_t **mpctxp); 500 /*%< 501 * Destroy a memory pool. 502 * 503 * Requires: 504 *\li mpctxp != NULL && *mpctxp is a valid pool. 505 *\li The pool has no un"put" allocations outstanding 506 */ 507 508 void 509 isc_mempool_setname(isc_mempool_t *mpctx, const char *name); 510 /*%< 511 * Associate a name with a memory pool. At most 15 characters may be used. 512 * 513 * Requires: 514 *\li mpctx is a valid pool. 515 *\li name != NULL; 516 */ 517 518 /* 519 * The following functions get/set various parameters. Note that due to 520 * the unlocked nature of pools these are potentially random values unless 521 * the imposed externally provided locking protocols are followed. 522 * 523 * Also note that the quota limits will not always take immediate effect. 524 * For instance, setting "maxalloc" to a number smaller than the currently 525 * allocated count is permitted. New allocations will be refused until 526 * the count drops below this threshold. 527 * 528 * All functions require (in addition to other requirements): 529 * mpctx is a valid memory pool 530 */ 531 532 unsigned int 533 isc_mempool_getfreemax(isc_mempool_t *mpctx); 534 /*%< 535 * Returns the maximum allowed size of the free list. 536 */ 537 538 void 539 isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit); 540 /*%< 541 * Sets the maximum allowed size of the free list. 542 */ 543 544 unsigned int 545 isc_mempool_getfreecount(isc_mempool_t *mpctx); 546 /*%< 547 * Returns current size of the free list. 548 */ 549 550 unsigned int 551 isc_mempool_getmaxalloc(isc_mempool_t *mpctx); 552 /*!< 553 * Returns the maximum allowed number of allocations. 554 */ 555 556 void 557 isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit); 558 /*%< 559 * Sets the maximum allowed number of allocations. 560 * 561 * Additional requirements: 562 *\li limit > 0 563 */ 564 565 unsigned int 566 isc_mempool_getallocated(isc_mempool_t *mpctx); 567 /*%< 568 * Returns the number of items allocated from this pool. 569 */ 570 571 unsigned int 572 isc_mempool_getfillcount(isc_mempool_t *mpctx); 573 /*%< 574 * Returns the number of items allocated as a block from the parent memory 575 * context when the free list is empty. 576 */ 577 578 void 579 isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit); 580 /*%< 581 * Sets the fillcount. 582 * 583 * Additional requirements: 584 *\li limit > 0 585 */ 586 587 #if defined(UNIT_TESTING) && defined(malloc) 588 /* 589 * cmocka.h redefined malloc as a macro, we #undef it 590 * to avoid replacing ISC_ATTR_MALLOC with garbage. 591 */ 592 #pragma push_macro("malloc") 593 #undef malloc 594 #define POP_MALLOC_MACRO 1 595 #endif 596 597 /* 598 * Pseudo-private functions for use via macros. Do not call directly. 599 */ 600 void ISCMEMFUNC(putanddetach)(isc_mem_t **, void *, size_t _ISC_MEM_FLARG); 601 void ISCMEMFUNC(put)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG); 602 void ISCMEMFUNC(free)(isc_mem_t *, void *_ISC_MEM_FLARG); 603 604 ISC_ATTR_RETURNS_NONNULL 605 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(put), 2) 606 void *ISCMEMFUNC(get)(isc_mem_t *, size_t _ISC_MEM_FLARG); 607 608 ISC_ATTR_RETURNS_NONNULL 609 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2) 610 void *ISCMEMFUNC(allocate)(isc_mem_t *, size_t _ISC_MEM_FLARG); 611 612 ISC_ATTR_RETURNS_NONNULL 613 ISC_ATTR_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2) 614 void *ISCMEMFUNC(reallocate)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG); 615 616 ISC_ATTR_RETURNS_NONNULL 617 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2) 618 char *ISCMEMFUNC(strdup)(isc_mem_t *, const char *_ISC_MEM_FLARG); 619 char *ISCMEMFUNC(strndup)(isc_mem_t *, const char *, size_t _ISC_MEM_FLARG); 620 621 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMPOOLFUNC(put), 2) 622 void *ISCMEMPOOLFUNC(get)(isc_mempool_t *_ISC_MEM_FLARG); 623 624 void ISCMEMPOOLFUNC(put)(isc_mempool_t *, void *_ISC_MEM_FLARG); 625 626 #ifdef POP_MALLOC_MACRO 627 /* 628 * Restore cmocka.h macro for malloc. 629 */ 630 #pragma pop_macro("malloc") 631 #endif 632 633 ISC_LANG_ENDDECLS 634 635 #endif /* ISC_MEM_H */ 636