1998-08-17 22:05:58 +00:00
|
|
|
/*
|
2010-03-04 23:50:34 +00:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
1998-12-12 20:48:14 +00:00
|
|
|
*
|
1998-08-17 22:05:58 +00:00
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
2021-06-03 08:37:05 +02:00
|
|
|
*
|
1998-08-17 22:05:58 +00:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
1998-08-17 22:05:58 +00:00
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
2009-09-01 00:22:28 +00:00
|
|
|
* information regarding copyright ownership.
|
1998-08-17 22:05:58 +00:00
|
|
|
*/
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*! \file */
|
2000-06-22 22:00:42 +00:00
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
#include <inttypes.h>
|
1999-06-08 02:38:30 +00:00
|
|
|
#include <limits.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
1998-12-12 19:25:20 +00:00
|
|
|
#include <stddef.h>
|
2025-06-04 18:14:23 +02:00
|
|
|
#include <stdint.h>
|
1998-08-17 22:05:58 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
1999-06-08 02:38:30 +00:00
|
|
|
|
2025-06-04 18:14:23 +02:00
|
|
|
#include <isc/atomic.h>
|
2018-11-16 12:23:36 +11:00
|
|
|
#include <isc/hash.h>
|
2001-06-04 19:33:39 +00:00
|
|
|
#include <isc/magic.h>
|
1998-12-11 20:38:46 +00:00
|
|
|
#include <isc/mem.h>
|
2018-11-16 12:23:36 +11:00
|
|
|
#include <isc/mutex.h>
|
2021-12-14 21:50:23 +01:00
|
|
|
#include <isc/os.h>
|
2023-06-06 15:15:31 +01:00
|
|
|
#include <isc/overflow.h>
|
2018-05-24 14:43:25 +02:00
|
|
|
#include <isc/refcount.h>
|
2018-11-16 12:23:36 +11:00
|
|
|
#include <isc/strerr.h>
|
2000-05-08 14:38:29 +00:00
|
|
|
#include <isc/string.h>
|
2025-06-04 18:14:23 +02:00
|
|
|
#include <isc/tid.h>
|
2021-02-04 20:19:09 +01:00
|
|
|
#include <isc/types.h>
|
2023-04-28 14:10:03 +01:00
|
|
|
#include <isc/urcu.h>
|
1999-12-16 22:24:22 +00:00
|
|
|
#include <isc/util.h>
|
2025-07-24 08:06:04 +02:00
|
|
|
#include <isc/uv.h>
|
2019-06-24 14:25:55 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_LIBXML2
|
|
|
|
#include <libxml/xmlwriter.h>
|
|
|
|
#define ISC_XMLCHAR (const xmlChar *)
|
|
|
|
#endif /* HAVE_LIBXML2 */
|
1998-08-18 19:28:30 +00:00
|
|
|
|
2019-06-24 12:21:47 +02:00
|
|
|
#ifdef HAVE_JSON_C
|
|
|
|
#include <json_object.h>
|
|
|
|
#endif /* HAVE_JSON_C */
|
|
|
|
|
2023-01-16 18:31:08 +02:00
|
|
|
/* On DragonFly BSD the header does not provide jemalloc API */
|
|
|
|
#if defined(HAVE_MALLOC_NP_H) && !defined(__DragonFly__)
|
Use system allocator when jemalloc is unavailable
This commit adds support for systems where the jemalloc library is not
available as a package, here's the quick summary:
* On Linux - the jemalloc is usually available as a package, if
configured --without-jemalloc, the shim would be used around
malloc(), free(), realloc() and malloc_usable_size()
* On macOS - the jemalloc is available from homebrew or macports, if
configured --without-jemalloc, the shim would be used around
malloc(), free(), realloc() and malloc_size()
* On FreeBSD - the jemalloc is *the* system allocator, we just need
to check for <malloc_np.h> header to get access to non-standard API
* On NetBSD - the jemalloc is *the* system allocator, we just need to
check for <jemalloc/jemalloc.h> header to get access to non-standard
API
* On a system hostile to users and developers (read OpenBSD) - the
jemalloc API is emulated by using ((size_t *)ptr)[-1] field to hold
the size information. The OpenBSD developers care only for
themselves, so why should we care about speed on OpenBSD?
2021-05-25 12:46:00 +02:00
|
|
|
#include <malloc_np.h>
|
2023-01-16 18:31:08 +02:00
|
|
|
#define JEMALLOC_API_SUPPORTED 1
|
Use system allocator when jemalloc is unavailable
This commit adds support for systems where the jemalloc library is not
available as a package, here's the quick summary:
* On Linux - the jemalloc is usually available as a package, if
configured --without-jemalloc, the shim would be used around
malloc(), free(), realloc() and malloc_usable_size()
* On macOS - the jemalloc is available from homebrew or macports, if
configured --without-jemalloc, the shim would be used around
malloc(), free(), realloc() and malloc_size()
* On FreeBSD - the jemalloc is *the* system allocator, we just need
to check for <malloc_np.h> header to get access to non-standard API
* On NetBSD - the jemalloc is *the* system allocator, we just need to
check for <jemalloc/jemalloc.h> header to get access to non-standard
API
* On a system hostile to users and developers (read OpenBSD) - the
jemalloc API is emulated by using ((size_t *)ptr)[-1] field to hold
the size information. The OpenBSD developers care only for
themselves, so why should we care about speed on OpenBSD?
2021-05-25 12:46:00 +02:00
|
|
|
#elif defined(HAVE_JEMALLOC)
|
2021-05-11 12:33:31 +02:00
|
|
|
#include <jemalloc/jemalloc.h>
|
2023-01-16 18:31:08 +02:00
|
|
|
#define JEMALLOC_API_SUPPORTED 1
|
Use system allocator when jemalloc is unavailable
This commit adds support for systems where the jemalloc library is not
available as a package, here's the quick summary:
* On Linux - the jemalloc is usually available as a package, if
configured --without-jemalloc, the shim would be used around
malloc(), free(), realloc() and malloc_usable_size()
* On macOS - the jemalloc is available from homebrew or macports, if
configured --without-jemalloc, the shim would be used around
malloc(), free(), realloc() and malloc_size()
* On FreeBSD - the jemalloc is *the* system allocator, we just need
to check for <malloc_np.h> header to get access to non-standard API
* On NetBSD - the jemalloc is *the* system allocator, we just need to
check for <jemalloc/jemalloc.h> header to get access to non-standard
API
* On a system hostile to users and developers (read OpenBSD) - the
jemalloc API is emulated by using ((size_t *)ptr)[-1] field to hold
the size information. The OpenBSD developers care only for
themselves, so why should we care about speed on OpenBSD?
2021-05-25 12:46:00 +02:00
|
|
|
#else
|
|
|
|
#include "jemalloc_shim.h"
|
|
|
|
#endif
|
|
|
|
|
2018-10-03 19:04:46 -07:00
|
|
|
#include "mem_p.h"
|
|
|
|
|
2019-09-06 12:46:57 +02:00
|
|
|
#define MCTXLOCK(m) LOCK(&m->lock)
|
|
|
|
#define MCTXUNLOCK(m) UNLOCK(&m->lock)
|
2005-06-04 05:32:50 +00:00
|
|
|
|
2001-06-28 01:51:20 +00:00
|
|
|
#ifndef ISC_MEM_DEBUGGING
|
|
|
|
#define ISC_MEM_DEBUGGING 0
|
|
|
|
#endif /* ifndef ISC_MEM_DEBUGGING */
|
2025-07-24 08:06:04 +02:00
|
|
|
|
|
|
|
static unsigned int mem_debugging = ISC_MEM_DEBUGGING;
|
2021-06-10 08:06:48 +02:00
|
|
|
unsigned int isc_mem_defaultflags = ISC_MEMFLAG_DEFAULT;
|
1999-10-27 20:55:21 +00:00
|
|
|
|
2023-12-21 11:12:54 +01:00
|
|
|
volatile void *isc__mem_malloc = mallocx;
|
|
|
|
|
2025-07-15 12:56:04 +02:00
|
|
|
isc_mem_t *isc_g_mctx = NULL;
|
|
|
|
|
1999-10-27 20:55:21 +00:00
|
|
|
/*
|
|
|
|
* Constants.
|
|
|
|
*/
|
|
|
|
|
2021-09-23 21:19:25 +02:00
|
|
|
#define ZERO_ALLOCATION_SIZE sizeof(void *)
|
|
|
|
#define DEBUG_TABLE_COUNT 512U
|
1999-10-27 20:55:21 +00:00
|
|
|
|
1998-08-17 22:05:58 +00:00
|
|
|
/*
|
|
|
|
* Types.
|
|
|
|
*/
|
2000-12-01 00:32:02 +00:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2000-07-26 19:06:20 +00:00
|
|
|
typedef struct debuglink debuglink_t;
|
|
|
|
struct debuglink {
|
copy __FILE__ when allocating memory
When allocating memory under -m trace|record, the __FILE__ pointer is
stored, so it can be printed out later in order to figure out in which
file an allocation leaked. (among others, like the line number).
However named crashes when called with -m record and using a plugin
leaking memory. The reason is that plugins are unloaded earlier than
when the leaked allocations are dumped (obviously, as it's done as late
as possible). In such circumstances, __FILE__ is dangling because the
dynamically loaded library (the plugin) is not in memory anymore.
Fix the crash by systematically copying the __FILE__ string
instead of copying the pointer. Of course, this make each allocation to
consume a bit more memory (and longer, as it needs to calculate the
length of __FILE__) but this occurs only under -m trace|record debugging
flags.
In term of unit test, because grepping in C is not fun, and because the
whole "syntax" of the dump output is tested in other tests, this simply
search for a substring in the whole buffer to make sure the expected
allocations are found.
2025-03-25 14:35:49 +01:00
|
|
|
size_t dlsize;
|
2000-07-26 19:06:20 +00:00
|
|
|
ISC_LINK(debuglink_t) link;
|
2017-08-24 10:58:20 +05:30
|
|
|
const void *ptr;
|
|
|
|
size_t size;
|
|
|
|
unsigned int line;
|
copy __FILE__ when allocating memory
When allocating memory under -m trace|record, the __FILE__ pointer is
stored, so it can be printed out later in order to figure out in which
file an allocation leaked. (among others, like the line number).
However named crashes when called with -m record and using a plugin
leaking memory. The reason is that plugins are unloaded earlier than
when the leaked allocations are dumped (obviously, as it's done as late
as possible). In such circumstances, __FILE__ is dangling because the
dynamically loaded library (the plugin) is not in memory anymore.
Fix the crash by systematically copying the __FILE__ string
instead of copying the pointer. Of course, this make each allocation to
consume a bit more memory (and longer, as it needs to calculate the
length of __FILE__) but this occurs only under -m trace|record debugging
flags.
In term of unit test, because grepping in C is not fun, and because the
whole "syntax" of the dump output is tested in other tests, this simply
search for a substring in the whole buffer to make sure the expected
allocations are found.
2025-03-25 14:35:49 +01:00
|
|
|
const char file[];
|
2000-07-26 19:06:20 +00:00
|
|
|
};
|
1998-08-17 22:05:58 +00:00
|
|
|
|
2017-08-24 10:58:20 +05:30
|
|
|
typedef ISC_LIST(debuglink_t) debuglist_t;
|
|
|
|
|
2024-09-09 13:59:43 +02:00
|
|
|
#define FLARG_PASS , func, file, line
|
|
|
|
#define FLARG , const char *func, const char *file, unsigned int line
|
2000-07-26 19:06:20 +00:00
|
|
|
#else /* if ISC_MEM_TRACKLINES */
|
|
|
|
#define FLARG_PASS
|
|
|
|
#define FLARG
|
|
|
|
#endif /* if ISC_MEM_TRACKLINES */
|
2000-02-01 00:18:35 +00:00
|
|
|
|
2000-07-26 19:06:20 +00:00
|
|
|
typedef struct element element;
|
2000-02-01 00:18:35 +00:00
|
|
|
struct element {
|
|
|
|
element *next;
|
|
|
|
};
|
1998-08-17 22:05:58 +00:00
|
|
|
|
2001-06-04 19:33:39 +00:00
|
|
|
#define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
|
|
|
|
#define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
|
1998-12-13 02:04:56 +00:00
|
|
|
|
2006-01-04 03:16:47 +00:00
|
|
|
/* List of all active memory contexts. */
|
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
static ISC_LIST(isc_mem_t) contexts;
|
2013-04-10 13:49:57 -07:00
|
|
|
|
2015-01-20 13:29:18 -08:00
|
|
|
static isc_mutex_t contextslock;
|
2006-01-04 03:16:47 +00:00
|
|
|
|
2025-06-04 18:14:23 +02:00
|
|
|
typedef union {
|
|
|
|
struct {
|
|
|
|
atomic_int_fast64_t inuse;
|
|
|
|
atomic_bool is_overmem;
|
|
|
|
};
|
|
|
|
char padding[ISC_OS_CACHELINE_SIZE];
|
|
|
|
} isc__mem_stat_t;
|
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
struct isc_mem {
|
|
|
|
unsigned int magic;
|
2005-06-04 05:32:50 +00:00
|
|
|
unsigned int flags;
|
2023-08-10 17:02:43 +03:00
|
|
|
unsigned int jemalloc_flags;
|
2022-09-23 13:49:31 +02:00
|
|
|
unsigned int debugging;
|
2008-04-02 02:37:42 +00:00
|
|
|
isc_mutex_t lock;
|
2019-09-06 11:31:15 +02:00
|
|
|
bool checkfree;
|
2018-05-24 14:43:25 +02:00
|
|
|
isc_refcount_t references;
|
2025-02-21 12:45:08 +01:00
|
|
|
char *name;
|
2021-07-22 06:14:32 +02:00
|
|
|
atomic_size_t hi_water;
|
|
|
|
atomic_size_t lo_water;
|
2021-02-04 20:19:09 +01:00
|
|
|
ISC_LIST(isc_mempool_t) pools;
|
2008-03-31 05:00:30 +00:00
|
|
|
unsigned int poolcnt;
|
2001-01-25 01:18:00 +00:00
|
|
|
|
2000-12-01 00:32:02 +00:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2001-08-30 05:40:04 +00:00
|
|
|
debuglist_t *debuglist;
|
2017-08-24 10:58:20 +05:30
|
|
|
size_t debuglistcnt;
|
2000-07-26 19:06:20 +00:00
|
|
|
#endif /* if ISC_MEM_TRACKLINES */
|
2001-06-11 20:27:16 +00:00
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
ISC_LINK(isc_mem_t) link;
|
2025-06-04 18:14:23 +02:00
|
|
|
|
|
|
|
isc__mem_stat_t *stat;
|
|
|
|
isc__mem_stat_t stat_s[ISC_TID_MAX + 1];
|
1999-06-08 02:38:30 +00:00
|
|
|
};
|
|
|
|
|
2001-06-04 19:33:39 +00:00
|
|
|
#define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p')
|
|
|
|
#define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC)
|
1999-06-08 02:38:30 +00:00
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
struct isc_mempool {
|
1999-09-15 17:47:08 +00:00
|
|
|
/* always unlocked */
|
2021-02-04 20:19:09 +01:00
|
|
|
unsigned int magic;
|
2021-05-12 21:16:17 +02:00
|
|
|
isc_mem_t *mctx; /*%< our memory context */
|
2021-02-04 20:19:09 +01:00
|
|
|
ISC_LINK(isc_mempool_t) link; /*%< next pool in this mem context */
|
2021-05-12 21:16:17 +02:00
|
|
|
element *items; /*%< low water item list */
|
|
|
|
size_t size; /*%< size of each item on this pool */
|
2021-07-09 14:01:22 +03:00
|
|
|
size_t allocated; /*%< # of items currently given out */
|
|
|
|
size_t freecount; /*%< # of items on reserved list */
|
|
|
|
size_t freemax; /*%< # of items allowed on free list */
|
|
|
|
size_t fillcount; /*%< # of items to fetch on each fill */
|
2005-04-27 04:57:32 +00:00
|
|
|
/*%< Stats only. */
|
2021-07-09 14:01:22 +03:00
|
|
|
size_t gets; /*%< # of requests to this pool */
|
|
|
|
/*%< Debugging only. */
|
2025-05-28 23:00:24 +02:00
|
|
|
char *name; /*%< printed name in stats reports */
|
1998-08-17 22:05:58 +00:00
|
|
|
};
|
|
|
|
|
1999-10-27 20:55:21 +00:00
|
|
|
/*
|
|
|
|
* Private Inline-able.
|
|
|
|
*/
|
1998-08-17 22:05:58 +00:00
|
|
|
|
2000-12-01 00:32:02 +00:00
|
|
|
#if !ISC_MEM_TRACKLINES
|
2024-09-09 13:59:43 +02:00
|
|
|
#define ADD_TRACE(mctx, ptr, size, func, file, line)
|
|
|
|
#define DELETE_TRACE(mctx, ptr, size, func, file, line)
|
2012-10-25 18:56:47 -07:00
|
|
|
#define ISC_MEMFUNC_SCOPE
|
2000-07-26 19:06:20 +00:00
|
|
|
#else /* if !ISC_MEM_TRACKLINES */
|
2017-04-22 08:25:10 +05:30
|
|
|
#define TRACE_OR_RECORD (ISC_MEM_DEBUGTRACE | ISC_MEM_DEBUGRECORD)
|
2021-02-04 21:56:49 +01:00
|
|
|
|
2022-09-23 13:49:31 +02:00
|
|
|
#define SHOULD_TRACE_OR_RECORD(mctx, ptr) \
|
|
|
|
(((mctx)->debugging & TRACE_OR_RECORD) != 0 && ptr != NULL)
|
2021-02-04 21:56:49 +01:00
|
|
|
|
2024-09-09 13:59:43 +02:00
|
|
|
#define ADD_TRACE(mctx, ptr, size, func, file, line) \
|
|
|
|
if (SHOULD_TRACE_OR_RECORD(mctx, ptr)) { \
|
|
|
|
add_trace_entry(mctx, ptr, size, func, file, line); \
|
2021-02-04 21:56:49 +01:00
|
|
|
}
|
|
|
|
|
2024-09-09 13:59:43 +02:00
|
|
|
#define DELETE_TRACE(mctx, ptr, size, func, file, line) \
|
|
|
|
if (SHOULD_TRACE_OR_RECORD(mctx, ptr)) { \
|
|
|
|
delete_trace_entry(mctx, ptr, size, func, file, line); \
|
2021-02-04 21:56:49 +01:00
|
|
|
}
|
2000-07-26 19:06:20 +00:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
static void
|
2021-02-04 20:19:09 +01:00
|
|
|
print_active(isc_mem_t *ctx, FILE *out);
|
2018-10-03 19:04:46 -07:00
|
|
|
#endif /* ISC_MEM_TRACKLINES */
|
|
|
|
|
|
|
|
#if ISC_MEM_TRACKLINES
|
2005-04-27 04:57:32 +00:00
|
|
|
/*!
|
2021-02-04 21:56:49 +01:00
|
|
|
* mctx must not be locked.
|
2000-07-26 19:06:20 +00:00
|
|
|
*/
|
2017-08-24 10:58:20 +05:30
|
|
|
static void
|
2021-02-04 20:19:09 +01:00
|
|
|
add_trace_entry(isc_mem_t *mctx, const void *ptr, size_t size FLARG) {
|
2021-05-12 21:16:17 +02:00
|
|
|
debuglink_t *dl = NULL;
|
2018-03-28 14:19:37 +02:00
|
|
|
uint32_t hash;
|
|
|
|
uint32_t idx;
|
2000-07-26 19:06:20 +00:00
|
|
|
|
copy __FILE__ when allocating memory
When allocating memory under -m trace|record, the __FILE__ pointer is
stored, so it can be printed out later in order to figure out in which
file an allocation leaked. (among others, like the line number).
However named crashes when called with -m record and using a plugin
leaking memory. The reason is that plugins are unloaded earlier than
when the leaked allocations are dumped (obviously, as it's done as late
as possible). In such circumstances, __FILE__ is dangling because the
dynamically loaded library (the plugin) is not in memory anymore.
Fix the crash by systematically copying the __FILE__ string
instead of copying the pointer. Of course, this make each allocation to
consume a bit more memory (and longer, as it needs to calculate the
length of __FILE__) but this occurs only under -m trace|record debugging
flags.
In term of unit test, because grepping in C is not fun, and because the
whole "syntax" of the dump output is tested in other tests, this simply
search for a substring in the whole buffer to make sure the expected
allocations are found.
2025-03-25 14:35:49 +01:00
|
|
|
/*
|
|
|
|
* "file" needs to be copied because it can be part of a dynamically
|
|
|
|
* loaded plugin which would be unloaded at the time the trace is
|
|
|
|
* dumped. Storing "file" pointer then leads to a dangling pointer
|
|
|
|
* dereference and a crash.
|
|
|
|
*/
|
|
|
|
size_t filelen = strlen(file) + 1;
|
|
|
|
size_t dlsize = STRUCT_FLEX_SIZE(dl, file, filelen);
|
|
|
|
|
2021-02-04 21:56:49 +01:00
|
|
|
MCTXLOCK(mctx);
|
|
|
|
|
2022-09-23 13:49:31 +02:00
|
|
|
if ((mctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
|
2024-09-09 13:59:43 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
"add %p size %zu func %s file %s line %u mctx %p\n",
|
|
|
|
ptr, size, func, file, line, mctx);
|
2018-11-23 21:35:01 +01:00
|
|
|
}
|
2000-07-26 19:06:20 +00:00
|
|
|
|
2001-08-30 05:40:04 +00:00
|
|
|
if (mctx->debuglist == NULL) {
|
2021-02-04 21:56:49 +01:00
|
|
|
goto unlock;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-26 19:06:20 +00:00
|
|
|
|
2020-02-18 09:40:21 +11:00
|
|
|
#ifdef __COVERITY__
|
|
|
|
/*
|
|
|
|
* Use simple conversion from pointer to hash to avoid
|
2023-09-12 16:35:29 +02:00
|
|
|
* tainting 'ptr' due to byte swap in isc_hash32.
|
2020-02-18 09:40:21 +11:00
|
|
|
*/
|
|
|
|
hash = (uintptr_t)ptr >> 3;
|
|
|
|
#else
|
2023-09-12 16:35:29 +02:00
|
|
|
hash = isc_hash32(&ptr, sizeof(ptr), true);
|
2020-02-18 09:40:21 +11:00
|
|
|
#endif
|
2017-08-24 10:58:20 +05:30
|
|
|
idx = hash % DEBUG_TABLE_COUNT;
|
|
|
|
|
copy __FILE__ when allocating memory
When allocating memory under -m trace|record, the __FILE__ pointer is
stored, so it can be printed out later in order to figure out in which
file an allocation leaked. (among others, like the line number).
However named crashes when called with -m record and using a plugin
leaking memory. The reason is that plugins are unloaded earlier than
when the leaked allocations are dumped (obviously, as it's done as late
as possible). In such circumstances, __FILE__ is dangling because the
dynamically loaded library (the plugin) is not in memory anymore.
Fix the crash by systematically copying the __FILE__ string
instead of copying the pointer. Of course, this make each allocation to
consume a bit more memory (and longer, as it needs to calculate the
length of __FILE__) but this occurs only under -m trace|record debugging
flags.
In term of unit test, because grepping in C is not fun, and because the
whole "syntax" of the dump output is tested in other tests, this simply
search for a substring in the whole buffer to make sure the expected
allocations are found.
2025-03-25 14:35:49 +01:00
|
|
|
dl = mallocx(dlsize, mctx->jemalloc_flags);
|
2000-07-26 19:06:20 +00:00
|
|
|
INSIST(dl != NULL);
|
|
|
|
|
|
|
|
ISC_LINK_INIT(dl, link);
|
2017-08-24 10:58:20 +05:30
|
|
|
dl->ptr = ptr;
|
|
|
|
dl->size = size;
|
|
|
|
dl->line = line;
|
copy __FILE__ when allocating memory
When allocating memory under -m trace|record, the __FILE__ pointer is
stored, so it can be printed out later in order to figure out in which
file an allocation leaked. (among others, like the line number).
However named crashes when called with -m record and using a plugin
leaking memory. The reason is that plugins are unloaded earlier than
when the leaked allocations are dumped (obviously, as it's done as late
as possible). In such circumstances, __FILE__ is dangling because the
dynamically loaded library (the plugin) is not in memory anymore.
Fix the crash by systematically copying the __FILE__ string
instead of copying the pointer. Of course, this make each allocation to
consume a bit more memory (and longer, as it needs to calculate the
length of __FILE__) but this occurs only under -m trace|record debugging
flags.
In term of unit test, because grepping in C is not fun, and because the
whole "syntax" of the dump output is tested in other tests, this simply
search for a substring in the whole buffer to make sure the expected
allocations are found.
2025-03-25 14:35:49 +01:00
|
|
|
dl->dlsize = dlsize;
|
|
|
|
strlcpy((char *)dl->file, file, filelen);
|
2000-07-26 19:06:20 +00:00
|
|
|
|
2017-08-24 10:58:20 +05:30
|
|
|
ISC_LIST_PREPEND(mctx->debuglist[idx], dl, link);
|
2008-03-31 05:00:30 +00:00
|
|
|
mctx->debuglistcnt++;
|
2021-02-04 21:56:49 +01:00
|
|
|
unlock:
|
|
|
|
MCTXUNLOCK(mctx);
|
2000-07-26 19:06:20 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 10:58:20 +05:30
|
|
|
static void
|
2024-09-09 13:59:43 +02:00
|
|
|
delete_trace_entry(isc_mem_t *mctx, const void *ptr, size_t size FLARG) {
|
2018-03-28 14:19:37 +02:00
|
|
|
uint32_t hash;
|
|
|
|
uint32_t idx;
|
2000-07-26 19:06:20 +00:00
|
|
|
|
2021-02-04 21:56:49 +01:00
|
|
|
MCTXLOCK(mctx);
|
|
|
|
|
2022-09-23 13:49:31 +02:00
|
|
|
if ((mctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
|
2024-09-09 13:59:43 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
"del %p size %zu func %s file %s line %u mctx %p\n",
|
|
|
|
ptr, size, func, file, line, mctx);
|
2018-11-23 21:35:01 +01:00
|
|
|
}
|
2000-07-26 19:06:20 +00:00
|
|
|
|
2001-08-30 05:40:04 +00:00
|
|
|
if (mctx->debuglist == NULL) {
|
2021-02-04 21:56:49 +01:00
|
|
|
goto unlock;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-26 19:06:20 +00:00
|
|
|
|
2020-02-18 09:40:21 +11:00
|
|
|
#ifdef __COVERITY__
|
|
|
|
/*
|
|
|
|
* Use simple conversion from pointer to hash to avoid
|
2023-09-12 16:35:29 +02:00
|
|
|
* tainting 'ptr' due to byte swap in isc_hash32.
|
2020-02-18 09:40:21 +11:00
|
|
|
*/
|
|
|
|
hash = (uintptr_t)ptr >> 3;
|
|
|
|
#else
|
2023-09-12 16:35:29 +02:00
|
|
|
hash = isc_hash32(&ptr, sizeof(ptr), true);
|
2020-02-18 09:40:21 +11:00
|
|
|
#endif
|
2017-08-24 10:58:20 +05:30
|
|
|
idx = hash % DEBUG_TABLE_COUNT;
|
|
|
|
|
2025-03-22 15:26:16 -07:00
|
|
|
ISC_LIST_FOREACH(mctx->debuglist[idx], dl, link) {
|
2021-10-14 10:33:24 +02:00
|
|
|
if (dl->ptr == ptr) {
|
2017-08-24 10:58:20 +05:30
|
|
|
ISC_LIST_UNLINK(mctx->debuglist[idx], dl, link);
|
copy __FILE__ when allocating memory
When allocating memory under -m trace|record, the __FILE__ pointer is
stored, so it can be printed out later in order to figure out in which
file an allocation leaked. (among others, like the line number).
However named crashes when called with -m record and using a plugin
leaking memory. The reason is that plugins are unloaded earlier than
when the leaked allocations are dumped (obviously, as it's done as late
as possible). In such circumstances, __FILE__ is dangling because the
dynamically loaded library (the plugin) is not in memory anymore.
Fix the crash by systematically copying the __FILE__ string
instead of copying the pointer. Of course, this make each allocation to
consume a bit more memory (and longer, as it needs to calculate the
length of __FILE__) but this occurs only under -m trace|record debugging
flags.
In term of unit test, because grepping in C is not fun, and because the
whole "syntax" of the dump output is tested in other tests, this simply
search for a substring in the whole buffer to make sure the expected
allocations are found.
2025-03-25 14:35:49 +01:00
|
|
|
sdallocx(dl, dl->dlsize, mctx->jemalloc_flags);
|
2021-02-04 21:56:49 +01:00
|
|
|
goto unlock;
|
2000-07-26 19:06:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we get here, we didn't find the item on the list. We're
|
|
|
|
* screwed.
|
|
|
|
*/
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2021-02-04 21:56:49 +01:00
|
|
|
unlock:
|
|
|
|
MCTXUNLOCK(mctx);
|
2000-07-26 19:06:20 +00:00
|
|
|
}
|
|
|
|
#endif /* ISC_MEM_TRACKLINES */
|
|
|
|
|
2021-09-23 21:19:25 +02:00
|
|
|
#define ADJUST_ZERO_ALLOCATION_SIZE(s) \
|
2021-10-14 10:33:24 +02:00
|
|
|
if (s == 0) { \
|
2021-09-23 21:19:25 +02:00
|
|
|
s = ZERO_ALLOCATION_SIZE; \
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*!
|
2001-01-25 01:18:00 +00:00
|
|
|
* Perform a malloc, doing memory filling and overrun detection as necessary.
|
|
|
|
*/
|
2021-10-11 13:43:12 +02:00
|
|
|
static void *
|
2021-12-14 21:50:23 +01:00
|
|
|
mem_get(isc_mem_t *ctx, size_t size, int flags) {
|
2021-09-23 21:19:25 +02:00
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
ADJUST_ZERO_ALLOCATION_SIZE(size);
|
|
|
|
|
2023-08-10 17:02:43 +03:00
|
|
|
ret = mallocx(size, flags | ctx->jemalloc_flags);
|
2021-09-29 10:58:58 +02:00
|
|
|
INSIST(ret != NULL);
|
2001-01-25 01:18:00 +00:00
|
|
|
|
2023-08-23 11:05:14 +02:00
|
|
|
if ((flags & ISC__MEM_ZERO) == 0 &&
|
|
|
|
(ctx->flags & ISC_MEMFLAG_FILL) != 0)
|
2022-06-03 12:23:49 +02:00
|
|
|
{
|
2021-05-11 14:00:12 +02:00
|
|
|
memset(ret, 0xbe, size); /* Mnemonic for "beef". */
|
2018-01-05 12:13:17 +11:00
|
|
|
}
|
2001-01-25 01:18:00 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*!
|
2001-01-25 01:18:00 +00:00
|
|
|
* Perform a free, doing memory filling and overrun detection as necessary.
|
|
|
|
*/
|
2012-11-02 11:16:32 +11:00
|
|
|
/* coverity[+free : arg-1] */
|
2021-10-11 13:43:12 +02:00
|
|
|
static void
|
2021-12-14 21:50:23 +01:00
|
|
|
mem_put(isc_mem_t *ctx, void *mem, size_t size, int flags) {
|
2021-09-23 21:19:25 +02:00
|
|
|
ADJUST_ZERO_ALLOCATION_SIZE(size);
|
|
|
|
|
2021-10-14 10:33:24 +02:00
|
|
|
if ((ctx->flags & ISC_MEMFLAG_FILL) != 0) {
|
2017-10-09 09:55:37 -07:00
|
|
|
memset(mem, 0xde, size); /* Mnemonic for "dead". */
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2023-08-10 17:02:43 +03:00
|
|
|
sdallocx(mem, size, flags | ctx->jemalloc_flags);
|
2001-01-25 01:18:00 +00:00
|
|
|
}
|
|
|
|
|
2021-10-11 13:43:12 +02:00
|
|
|
static void *
|
2021-12-14 21:50:23 +01:00
|
|
|
mem_realloc(isc_mem_t *ctx, void *old_ptr, size_t old_size, size_t new_size,
|
|
|
|
int flags) {
|
2021-09-22 18:48:03 +02:00
|
|
|
void *new_ptr = NULL;
|
|
|
|
|
2021-09-23 21:19:25 +02:00
|
|
|
ADJUST_ZERO_ALLOCATION_SIZE(new_size);
|
|
|
|
|
2023-08-10 17:02:43 +03:00
|
|
|
new_ptr = rallocx(old_ptr, new_size, flags | ctx->jemalloc_flags);
|
2021-09-29 10:58:58 +02:00
|
|
|
INSIST(new_ptr != NULL);
|
2021-09-22 18:48:03 +02:00
|
|
|
|
2023-08-23 11:05:14 +02:00
|
|
|
if ((flags & ISC__MEM_ZERO) == 0 &&
|
|
|
|
(ctx->flags & ISC_MEMFLAG_FILL) != 0)
|
2022-06-03 12:23:49 +02:00
|
|
|
{
|
2025-06-05 12:19:43 +02:00
|
|
|
if (new_size > old_size) {
|
|
|
|
size_t diff_size = new_size - old_size;
|
|
|
|
void *diff_ptr = (uint8_t *)new_ptr + old_size;
|
2021-09-22 18:48:03 +02:00
|
|
|
/* Mnemonic for "beef". */
|
|
|
|
memset(diff_ptr, 0xbe, diff_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_ptr;
|
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*!
|
2001-01-25 01:18:00 +00:00
|
|
|
* Update internal counters after a memory get.
|
|
|
|
*/
|
2021-10-11 13:43:12 +02:00
|
|
|
static void
|
2021-02-04 20:19:09 +01:00
|
|
|
mem_getstats(isc_mem_t *ctx, size_t size) {
|
2025-06-04 18:14:23 +02:00
|
|
|
atomic_fetch_add_relaxed(&ctx->stat[isc_tid()].inuse, size);
|
2001-01-25 01:18:00 +00:00
|
|
|
}
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*!
|
2001-01-25 01:18:00 +00:00
|
|
|
* Update internal counters after a memory put.
|
|
|
|
*/
|
2021-10-11 13:43:12 +02:00
|
|
|
static void
|
2023-01-19 12:05:44 +01:00
|
|
|
mem_putstats(isc_mem_t *ctx, size_t size) {
|
2025-06-04 18:14:23 +02:00
|
|
|
atomic_fetch_sub_relaxed(&ctx->stat[isc_tid()].inuse, size);
|
2001-01-25 01:18:00 +00:00
|
|
|
}
|
|
|
|
|
2000-06-01 17:20:56 +00:00
|
|
|
/*
|
|
|
|
* Private.
|
|
|
|
*/
|
|
|
|
|
2025-07-24 08:06:04 +02:00
|
|
|
static bool
|
|
|
|
debugging_enabled(const char *name) {
|
|
|
|
char env_buf[256];
|
|
|
|
size_t env_size = sizeof(env_buf);
|
|
|
|
|
|
|
|
int r = uv_os_getenv(name, env_buf, &env_size);
|
|
|
|
switch (r) {
|
|
|
|
case 0:
|
|
|
|
return true;
|
|
|
|
case UV_ENOENT:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
UV_RUNTIME_CHECK(uv_os_getenv, r);
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-04 13:17:31 +01:00
|
|
|
void
|
|
|
|
isc__mem_initialize(void) {
|
2022-06-03 12:23:49 +02:00
|
|
|
/*
|
|
|
|
* Check if the values copied from jemalloc still match
|
|
|
|
*/
|
2023-01-16 18:31:08 +02:00
|
|
|
#ifdef JEMALLOC_API_SUPPORTED
|
2023-08-23 11:05:14 +02:00
|
|
|
RUNTIME_CHECK(ISC__MEM_ZERO == MALLOCX_ZERO);
|
2023-01-16 18:31:08 +02:00
|
|
|
#endif /* JEMALLOC_API_SUPPORTED */
|
2022-06-03 12:23:49 +02:00
|
|
|
|
2018-11-16 15:33:22 +01:00
|
|
|
isc_mutex_init(&contextslock);
|
2006-01-04 03:16:47 +00:00
|
|
|
ISC_LIST_INIT(contexts);
|
2025-07-24 08:06:04 +02:00
|
|
|
|
|
|
|
if (debugging_enabled("ISC_MEM_DEBUGTRACE")) {
|
|
|
|
mem_debugging |= ISC_MEM_DEBUGTRACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debugging_enabled("ISC_MEM_DEBUGRECORD")) {
|
|
|
|
mem_debugging |= ISC_MEM_DEBUGRECORD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debugging_enabled("ISC_MEM_DEBUGUSAGE")) {
|
|
|
|
mem_debugging |= ISC_MEM_DEBUGUSAGE;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_mem_create("default", &isc_g_mctx);
|
2006-01-04 03:16:47 +00:00
|
|
|
}
|
|
|
|
|
2021-02-09 17:44:40 +01:00
|
|
|
void
|
2025-02-04 13:17:31 +01:00
|
|
|
isc__mem_shutdown(void) {
|
2024-02-07 09:23:50 +01:00
|
|
|
bool empty;
|
|
|
|
|
2025-03-09 09:13:16 +01:00
|
|
|
rcu_barrier();
|
|
|
|
|
2025-07-24 08:06:04 +02:00
|
|
|
isc_mem_detach(&isc_g_mctx);
|
|
|
|
|
2021-02-09 17:44:40 +01:00
|
|
|
isc__mem_checkdestroyed();
|
|
|
|
|
2024-02-07 09:23:50 +01:00
|
|
|
LOCK(&contextslock);
|
|
|
|
empty = ISC_LIST_EMPTY(contexts);
|
|
|
|
UNLOCK(&contextslock);
|
|
|
|
|
|
|
|
if (empty) {
|
|
|
|
isc_mutex_destroy(&contextslock);
|
|
|
|
}
|
2021-02-09 17:44:40 +01:00
|
|
|
}
|
|
|
|
|
2025-07-24 08:06:04 +02:00
|
|
|
void
|
|
|
|
isc_mem_setdebugging(isc_mem_t *ctx, unsigned int debugging) {
|
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
|
|
|
REQUIRE(isc_mem_inuse(ctx) == 0);
|
|
|
|
|
|
|
|
ctx->debugging = debugging;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
isc_mem_debugon(unsigned int debugging) {
|
|
|
|
unsigned int old_mem_debugging = mem_debugging;
|
|
|
|
|
|
|
|
if (debugging != 0) {
|
|
|
|
mem_debugging |= debugging;
|
|
|
|
|
|
|
|
isc_mem_setdebugging(isc_g_mctx, mem_debugging);
|
|
|
|
}
|
|
|
|
|
|
|
|
return old_mem_debugging;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
isc_mem_debugoff(unsigned int debugging) {
|
|
|
|
unsigned int old_mem_debugging = mem_debugging;
|
|
|
|
|
|
|
|
if (debugging != 0) {
|
|
|
|
mem_debugging &= ~debugging;
|
|
|
|
|
|
|
|
isc_mem_setdebugging(isc_g_mctx, mem_debugging);
|
|
|
|
}
|
|
|
|
|
|
|
|
return old_mem_debugging;
|
|
|
|
}
|
|
|
|
|
2019-09-06 11:31:15 +02:00
|
|
|
static void
|
2025-02-21 12:45:08 +01:00
|
|
|
mem_create(const char *name, isc_mem_t **ctxp, unsigned int debugging,
|
|
|
|
unsigned int flags, unsigned int jemalloc_flags) {
|
2021-05-12 21:16:17 +02:00
|
|
|
isc_mem_t *ctx = NULL;
|
2000-06-01 17:20:56 +00:00
|
|
|
|
2021-05-12 21:16:17 +02:00
|
|
|
REQUIRE(ctxp != NULL && *ctxp == NULL);
|
2025-02-21 12:45:08 +01:00
|
|
|
REQUIRE(name != NULL);
|
2020-02-01 17:59:19 +01:00
|
|
|
|
2023-08-10 17:02:43 +03:00
|
|
|
ctx = mallocx(sizeof(*ctx), jemalloc_flags);
|
2021-09-29 10:58:58 +02:00
|
|
|
INSIST(ctx != NULL);
|
2000-06-01 17:20:56 +00:00
|
|
|
|
2021-02-04 21:56:49 +01:00
|
|
|
*ctx = (isc_mem_t){
|
|
|
|
.magic = MEM_MAGIC,
|
2022-09-23 13:49:31 +02:00
|
|
|
.debugging = debugging,
|
2021-02-04 21:56:49 +01:00
|
|
|
.flags = flags,
|
2023-08-10 17:02:43 +03:00
|
|
|
.jemalloc_flags = jemalloc_flags,
|
2021-02-04 21:56:49 +01:00
|
|
|
.checkfree = true,
|
2025-02-21 12:45:08 +01:00
|
|
|
.name = strdup(name),
|
2021-02-04 21:56:49 +01:00
|
|
|
};
|
2005-03-15 01:11:01 +00:00
|
|
|
|
2021-02-04 21:56:49 +01:00
|
|
|
isc_mutex_init(&ctx->lock);
|
2018-05-24 14:43:25 +02:00
|
|
|
isc_refcount_init(&ctx->references, 1);
|
2001-01-25 01:18:00 +00:00
|
|
|
|
2025-06-04 18:14:23 +02:00
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(ctx->stat_s); i++) {
|
|
|
|
atomic_init(&ctx->stat_s[i].inuse, 0);
|
|
|
|
atomic_init(&ctx->stat_s[i].is_overmem, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reserve the [-1] index for ISC_TID_UNKNOWN */
|
|
|
|
ctx->stat = &ctx->stat_s[1];
|
|
|
|
|
2021-07-22 06:14:32 +02:00
|
|
|
atomic_init(&ctx->hi_water, 0);
|
|
|
|
atomic_init(&ctx->lo_water, 0);
|
2021-05-26 17:55:43 +10:00
|
|
|
|
2021-02-04 21:56:49 +01:00
|
|
|
ISC_LIST_INIT(ctx->pools);
|
2001-01-25 01:18:00 +00:00
|
|
|
|
2000-12-01 00:52:38 +00:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2022-09-23 13:49:31 +02:00
|
|
|
if ((ctx->debugging & ISC_MEM_DEBUGRECORD) != 0) {
|
2001-08-30 05:40:04 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
2023-08-10 17:02:43 +03:00
|
|
|
ctx->debuglist = mallocx(
|
|
|
|
ISC_CHECKED_MUL(DEBUG_TABLE_COUNT, sizeof(debuglist_t)),
|
|
|
|
jemalloc_flags);
|
2021-09-29 10:58:58 +02:00
|
|
|
INSIST(ctx->debuglist != NULL);
|
|
|
|
|
2017-08-24 10:58:20 +05:30
|
|
|
for (i = 0; i < DEBUG_TABLE_COUNT; i++) {
|
2001-08-30 05:40:04 +00:00
|
|
|
ISC_LIST_INIT(ctx->debuglist[i]);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-08-30 05:40:04 +00:00
|
|
|
}
|
2000-07-26 19:06:20 +00:00
|
|
|
#endif /* if ISC_MEM_TRACKLINES */
|
2000-06-01 17:20:56 +00:00
|
|
|
|
2015-01-20 13:29:18 -08:00
|
|
|
LOCK(&contextslock);
|
2006-01-04 03:16:47 +00:00
|
|
|
ISC_LIST_INITANDAPPEND(contexts, ctx, link);
|
2015-01-20 13:29:18 -08:00
|
|
|
UNLOCK(&contextslock);
|
2006-01-04 03:16:47 +00:00
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
*ctxp = ctx;
|
2000-06-01 17:20:56 +00:00
|
|
|
}
|
|
|
|
|
2019-09-06 11:31:15 +02:00
|
|
|
/*
|
|
|
|
* Public.
|
|
|
|
*/
|
|
|
|
|
2000-06-01 17:20:56 +00:00
|
|
|
static void
|
2024-09-09 12:14:05 +02:00
|
|
|
mem_destroy(isc_mem_t *ctx) {
|
|
|
|
isc_refcount_destroy(&ctx->references);
|
|
|
|
|
2015-01-20 13:29:18 -08:00
|
|
|
LOCK(&contextslock);
|
2006-01-04 03:16:47 +00:00
|
|
|
ISC_LIST_UNLINK(contexts, ctx, link);
|
2015-01-20 13:29:18 -08:00
|
|
|
UNLOCK(&contextslock);
|
2006-01-04 03:16:47 +00:00
|
|
|
|
2025-06-04 18:14:23 +02:00
|
|
|
if (ctx->checkfree) {
|
|
|
|
INSIST(isc_mem_inuse(ctx) == 0);
|
|
|
|
}
|
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
ctx->magic = 0;
|
2010-05-12 00:46:55 +00:00
|
|
|
|
2000-06-01 17:20:56 +00:00
|
|
|
INSIST(ISC_LIST_EMPTY(ctx->pools));
|
2001-01-25 01:18:00 +00:00
|
|
|
|
2000-12-01 00:52:38 +00:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2021-10-14 10:33:24 +02:00
|
|
|
if (ctx->debuglist != NULL) {
|
2023-01-19 12:00:04 +01:00
|
|
|
for (size_t i = 0; i < DEBUG_TABLE_COUNT; i++) {
|
2025-05-23 13:02:22 -07:00
|
|
|
ISC_LIST_FOREACH(ctx->debuglist[i], dl, link) {
|
2017-08-24 10:58:20 +05:30
|
|
|
if (ctx->checkfree && dl->ptr != NULL) {
|
2001-08-30 05:40:04 +00:00
|
|
|
print_active(ctx, stderr);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-08-24 10:58:20 +05:30
|
|
|
INSIST(!ctx->checkfree || dl->ptr == NULL);
|
|
|
|
|
|
|
|
ISC_LIST_UNLINK(ctx->debuglist[i], dl, link);
|
2023-08-10 17:02:43 +03:00
|
|
|
sdallocx(dl, sizeof(*dl), ctx->jemalloc_flags);
|
2001-08-30 05:40:04 +00:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-08-24 10:58:20 +05:30
|
|
|
|
2023-08-10 17:02:43 +03:00
|
|
|
sdallocx(
|
|
|
|
ctx->debuglist,
|
|
|
|
ISC_CHECKED_MUL(DEBUG_TABLE_COUNT, sizeof(debuglist_t)),
|
|
|
|
ctx->jemalloc_flags);
|
2000-11-25 06:40:54 +00:00
|
|
|
}
|
2000-07-26 19:06:20 +00:00
|
|
|
#endif /* if ISC_MEM_TRACKLINES */
|
2000-06-01 17:20:56 +00:00
|
|
|
|
2025-02-21 12:45:08 +01:00
|
|
|
free(ctx->name);
|
|
|
|
|
2019-09-06 12:46:57 +02:00
|
|
|
isc_mutex_destroy(&ctx->lock);
|
|
|
|
|
2023-08-10 17:02:43 +03:00
|
|
|
sdallocx(ctx, sizeof(*ctx), ctx->jemalloc_flags);
|
2000-06-01 17:20:56 +00:00
|
|
|
}
|
|
|
|
|
2024-09-09 12:14:05 +02:00
|
|
|
#if ISC_MEM_TRACE
|
|
|
|
ISC_REFCOUNT_TRACE_IMPL(isc_mem, mem_destroy);
|
|
|
|
#else
|
|
|
|
ISC_REFCOUNT_IMPL(isc_mem, mem_destroy);
|
2021-05-11 12:18:56 +02:00
|
|
|
#endif
|
2000-06-01 17:20:56 +00:00
|
|
|
|
2000-09-05 03:30:19 +00:00
|
|
|
/*
|
|
|
|
* isc_mem_putanddetach() is the equivalent of:
|
|
|
|
*
|
|
|
|
* mctx = NULL;
|
|
|
|
* isc_mem_attach(ptr->mctx, &mctx);
|
|
|
|
* isc_mem_detach(&ptr->mctx);
|
|
|
|
* isc_mem_put(mctx, ptr, sizeof(*ptr);
|
|
|
|
* isc_mem_detach(&mctx);
|
|
|
|
*/
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
2021-12-14 21:50:23 +01:00
|
|
|
isc__mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size,
|
2022-06-03 12:23:49 +02:00
|
|
|
int flags FLARG) {
|
2018-08-28 10:18:59 +02:00
|
|
|
REQUIRE(ctxp != NULL && VALID_CONTEXT(*ctxp));
|
2000-09-05 03:30:19 +00:00
|
|
|
REQUIRE(ptr != NULL);
|
2021-09-23 21:19:25 +02:00
|
|
|
REQUIRE(size != 0);
|
2020-02-01 17:59:19 +01:00
|
|
|
|
2024-02-07 09:23:50 +01:00
|
|
|
isc_mem_t *ctx = *ctxp;
|
2000-09-05 03:30:19 +00:00
|
|
|
*ctxp = NULL;
|
|
|
|
|
2024-02-07 09:23:50 +01:00
|
|
|
isc__mem_put(ctx, ptr, size, flags FLARG_PASS);
|
2024-09-09 12:14:05 +02:00
|
|
|
#if ISC_MEM_TRACE
|
2024-09-09 13:59:43 +02:00
|
|
|
isc_mem__detach(&ctx, func, file, line);
|
2024-09-09 12:14:05 +02:00
|
|
|
#else
|
|
|
|
isc_mem_detach(&ctx);
|
|
|
|
#endif
|
2024-02-07 09:23:50 +01:00
|
|
|
}
|
2012-11-02 15:57:56 +11:00
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void *
|
2022-06-03 12:23:49 +02:00
|
|
|
isc__mem_get(isc_mem_t *ctx, size_t size, int flags FLARG) {
|
2021-05-12 21:16:17 +02:00
|
|
|
void *ptr = NULL;
|
2000-07-26 19:06:20 +00:00
|
|
|
|
2021-05-12 21:16:17 +02:00
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
|
|
|
|
2022-06-03 12:23:49 +02:00
|
|
|
ptr = mem_get(ctx, size, flags);
|
2001-01-25 01:18:00 +00:00
|
|
|
|
2021-06-10 10:18:24 +02:00
|
|
|
mem_getstats(ctx, size);
|
2024-09-09 13:59:43 +02:00
|
|
|
ADD_TRACE(ctx, ptr, size, func, file, line);
|
2017-08-24 10:58:20 +05:30
|
|
|
|
1998-08-17 22:05:58 +00:00
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
2022-06-03 12:23:49 +02:00
|
|
|
isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size, int flags FLARG) {
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
2020-02-01 17:59:19 +01:00
|
|
|
|
2024-09-09 13:59:43 +02:00
|
|
|
DELETE_TRACE(ctx, ptr, size, func, file, line);
|
2012-11-02 15:57:56 +11:00
|
|
|
|
2023-01-19 12:05:44 +01:00
|
|
|
mem_putstats(ctx, size);
|
2022-06-03 12:23:49 +02:00
|
|
|
mem_put(ctx, ptr, size, flags);
|
2008-02-07 02:41:26 +00:00
|
|
|
}
|
|
|
|
|
2001-02-13 13:20:37 +00:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2001-02-13 06:21:32 +00:00
|
|
|
static void
|
2021-02-04 20:19:09 +01:00
|
|
|
print_active(isc_mem_t *mctx, FILE *out) {
|
2001-08-30 05:40:04 +00:00
|
|
|
if (mctx->debuglist != NULL) {
|
2017-08-24 10:58:20 +05:30
|
|
|
unsigned int i;
|
2018-04-17 08:29:14 -07:00
|
|
|
bool found;
|
2001-02-13 06:21:32 +00:00
|
|
|
|
2021-02-04 21:56:49 +01:00
|
|
|
fprintf(out, "Dump of all outstanding memory "
|
|
|
|
"allocations:\n");
|
2018-04-17 08:29:14 -07:00
|
|
|
found = false;
|
2017-08-24 10:58:20 +05:30
|
|
|
for (i = 0; i < DEBUG_TABLE_COUNT; i++) {
|
2025-03-22 15:26:16 -07:00
|
|
|
ISC_LIST_FOREACH(mctx->debuglist[i], dl, link) {
|
2018-04-17 08:29:14 -07:00
|
|
|
found = true;
|
2018-11-23 21:35:01 +01:00
|
|
|
if (dl->ptr != NULL) {
|
|
|
|
fprintf(out,
|
2021-02-04 21:56:49 +01:00
|
|
|
"\tptr %p size %zu "
|
|
|
|
"file %s "
|
2018-11-23 21:35:01 +01:00
|
|
|
"line %u\n",
|
2017-08-24 10:58:20 +05:30
|
|
|
dl->ptr, dl->size, dl->file,
|
|
|
|
dl->line);
|
2018-11-23 21:35:01 +01:00
|
|
|
}
|
2001-08-30 05:40:04 +00:00
|
|
|
}
|
2001-02-13 06:21:32 +00:00
|
|
|
}
|
2017-08-24 10:58:20 +05:30
|
|
|
|
2018-11-23 21:35:01 +01:00
|
|
|
if (!found) {
|
2020-04-02 18:51:06 -07:00
|
|
|
fprintf(out, "\tNone.\n");
|
2018-11-23 21:35:01 +01:00
|
|
|
}
|
2001-02-13 06:21:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* if ISC_MEM_TRACKLINES */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print the stats[] on the stream "out" with suitable formatting.
|
|
|
|
*/
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
2021-02-04 20:19:09 +01:00
|
|
|
isc_mem_stats(isc_mem_t *ctx, FILE *out) {
|
2021-05-12 21:16:17 +02:00
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
1998-08-17 22:05:58 +00:00
|
|
|
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXLOCK(ctx);
|
1998-08-17 22:05:58 +00:00
|
|
|
|
1999-09-15 17:47:08 +00:00
|
|
|
/*
|
2021-02-04 21:56:49 +01:00
|
|
|
* Note that since a pool can be locked now, these stats might
|
|
|
|
* be somewhat off if the pool is in active use at the time the
|
|
|
|
* stats are dumped. The link fields are protected by the
|
|
|
|
* isc_mem_t's lock, however, so walking this list and
|
|
|
|
* extracting integers from stats fields is always safe.
|
1999-09-15 17:47:08 +00:00
|
|
|
*/
|
2025-03-22 15:26:16 -07:00
|
|
|
if (!ISC_LIST_EMPTY(ctx->pools)) {
|
2020-04-02 18:51:06 -07:00
|
|
|
fprintf(out, "[Pool statistics]\n");
|
2021-05-13 00:29:11 +02:00
|
|
|
fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %1s\n", "name",
|
|
|
|
"size", "allocated", "freecount", "freemax",
|
|
|
|
"fillcount", "gets", "L");
|
1999-06-08 02:38:30 +00:00
|
|
|
}
|
2025-03-22 15:26:16 -07:00
|
|
|
ISC_LIST_FOREACH(ctx->pools, pool, link) {
|
2021-02-04 21:56:49 +01:00
|
|
|
fprintf(out,
|
|
|
|
"%15s %10zu %10zu %10zu %10zu %10zu %10zu %10zu %s\n",
|
2021-07-09 14:01:22 +03:00
|
|
|
pool->name, pool->size, (size_t)0, pool->allocated,
|
|
|
|
pool->freecount, pool->freemax, pool->fillcount,
|
|
|
|
pool->gets, "N");
|
1998-08-17 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
2001-02-13 13:20:37 +00:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2001-02-13 06:21:32 +00:00
|
|
|
print_active(ctx, out);
|
2000-07-26 19:06:20 +00:00
|
|
|
#endif /* if ISC_MEM_TRACKLINES */
|
|
|
|
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXUNLOCK(ctx);
|
1998-08-17 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void *
|
2022-06-03 12:23:49 +02:00
|
|
|
isc__mem_allocate(isc_mem_t *ctx, size_t size, int flags FLARG) {
|
2021-05-12 21:16:17 +02:00
|
|
|
void *ptr = NULL;
|
2000-02-26 19:59:30 +00:00
|
|
|
|
2021-05-12 21:16:17 +02:00
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
|
|
|
|
2022-06-03 12:23:49 +02:00
|
|
|
ptr = mem_get(ctx, size, flags);
|
2021-05-11 14:00:12 +02:00
|
|
|
|
2021-09-23 21:19:25 +02:00
|
|
|
/* Recalculate the real allocated size */
|
2023-08-10 17:02:43 +03:00
|
|
|
size = sallocx(ptr, flags | ctx->jemalloc_flags);
|
2001-01-25 01:18:00 +00:00
|
|
|
|
2021-05-11 14:00:12 +02:00
|
|
|
mem_getstats(ctx, size);
|
2024-09-09 13:59:43 +02:00
|
|
|
ADD_TRACE(ctx, ptr, size, func, file, line);
|
2010-08-11 22:54:58 +00:00
|
|
|
|
2021-05-11 14:00:12 +02:00
|
|
|
return ptr;
|
2000-02-26 19:59:30 +00:00
|
|
|
}
|
|
|
|
|
2021-09-22 18:48:03 +02:00
|
|
|
void *
|
2021-12-14 21:50:23 +01:00
|
|
|
isc__mem_reget(isc_mem_t *ctx, void *old_ptr, size_t old_size, size_t new_size,
|
2022-06-03 12:23:49 +02:00
|
|
|
int flags FLARG) {
|
2021-09-22 18:48:03 +02:00
|
|
|
void *new_ptr = NULL;
|
|
|
|
|
2021-10-14 10:33:24 +02:00
|
|
|
if (old_ptr == NULL) {
|
2021-09-22 18:48:03 +02:00
|
|
|
REQUIRE(old_size == 0);
|
2022-06-03 12:23:49 +02:00
|
|
|
new_ptr = isc__mem_get(ctx, new_size, flags FLARG_PASS);
|
2021-10-14 10:33:24 +02:00
|
|
|
} else if (new_size == 0) {
|
2022-06-03 12:23:49 +02:00
|
|
|
isc__mem_put(ctx, old_ptr, old_size, flags FLARG_PASS);
|
2021-09-22 18:48:03 +02:00
|
|
|
} else {
|
2024-09-09 13:59:43 +02:00
|
|
|
DELETE_TRACE(ctx, old_ptr, old_size, func, file, line);
|
2023-01-19 12:05:44 +01:00
|
|
|
mem_putstats(ctx, old_size);
|
2021-09-22 18:48:03 +02:00
|
|
|
|
2022-06-03 12:23:49 +02:00
|
|
|
new_ptr = mem_realloc(ctx, old_ptr, old_size, new_size, flags);
|
2021-09-22 18:48:03 +02:00
|
|
|
|
|
|
|
mem_getstats(ctx, new_size);
|
2024-09-09 13:59:43 +02:00
|
|
|
ADD_TRACE(ctx, new_ptr, new_size, func, file, line);
|
2021-09-22 18:48:03 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We want to postpone the call to water in edge case
|
|
|
|
* where the realloc will exactly hit on the boundary of
|
|
|
|
* the water and we would call water twice.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_ptr;
|
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void *
|
2022-06-03 12:23:49 +02:00
|
|
|
isc__mem_reallocate(isc_mem_t *ctx, void *old_ptr, size_t new_size,
|
|
|
|
int flags FLARG) {
|
2009-02-11 03:04:18 +00:00
|
|
|
void *new_ptr = NULL;
|
|
|
|
|
2021-05-12 21:16:17 +02:00
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
|
|
|
|
2021-10-14 10:33:24 +02:00
|
|
|
if (old_ptr == NULL) {
|
2022-06-03 12:23:49 +02:00
|
|
|
new_ptr = isc__mem_allocate(ctx, new_size, flags FLARG_PASS);
|
2021-10-14 10:33:24 +02:00
|
|
|
} else if (new_size == 0) {
|
2022-06-03 12:23:49 +02:00
|
|
|
isc__mem_free(ctx, old_ptr, flags FLARG_PASS);
|
2021-05-11 14:00:12 +02:00
|
|
|
} else {
|
2023-08-10 17:02:43 +03:00
|
|
|
size_t old_size = sallocx(old_ptr, flags | ctx->jemalloc_flags);
|
2021-05-11 14:00:12 +02:00
|
|
|
|
2024-09-09 13:59:43 +02:00
|
|
|
DELETE_TRACE(ctx, old_ptr, old_size, func, file, line);
|
2023-01-19 12:05:44 +01:00
|
|
|
mem_putstats(ctx, old_size);
|
2021-05-11 14:00:12 +02:00
|
|
|
|
2022-06-03 12:23:49 +02:00
|
|
|
new_ptr = mem_realloc(ctx, old_ptr, old_size, new_size, flags);
|
2021-05-11 14:00:12 +02:00
|
|
|
|
|
|
|
/* Recalculate the real allocated size */
|
2023-08-10 17:02:43 +03:00
|
|
|
new_size = sallocx(new_ptr, flags | ctx->jemalloc_flags);
|
2021-05-11 14:00:12 +02:00
|
|
|
|
|
|
|
mem_getstats(ctx, new_size);
|
2024-09-09 13:59:43 +02:00
|
|
|
ADD_TRACE(ctx, new_ptr, new_size, func, file, line);
|
2021-05-11 14:00:12 +02:00
|
|
|
|
|
|
|
/*
|
2021-06-10 10:18:24 +02:00
|
|
|
* We want to postpone the call to water in edge case
|
|
|
|
* where the realloc will exactly hit on the boundary of
|
|
|
|
* the water and we would call water twice.
|
2021-05-11 14:00:12 +02:00
|
|
|
*/
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-02-11 03:04:18 +00:00
|
|
|
|
|
|
|
return new_ptr;
|
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
2022-06-03 12:23:49 +02:00
|
|
|
isc__mem_free(isc_mem_t *ctx, void *ptr, int flags FLARG) {
|
2021-06-10 10:18:24 +02:00
|
|
|
size_t size = 0;
|
2021-05-12 21:16:17 +02:00
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
2022-06-13 12:00:01 +01:00
|
|
|
REQUIRE(ptr != NULL);
|
2020-02-01 17:59:19 +01:00
|
|
|
|
2023-08-10 17:02:43 +03:00
|
|
|
size = sallocx(ptr, flags | ctx->jemalloc_flags);
|
2001-01-25 01:18:00 +00:00
|
|
|
|
2024-09-09 13:59:43 +02:00
|
|
|
DELETE_TRACE(ctx, ptr, size, func, file, line);
|
2012-11-02 15:57:56 +11:00
|
|
|
|
2023-01-19 12:05:44 +01:00
|
|
|
mem_putstats(ctx, size);
|
2022-06-03 12:23:49 +02:00
|
|
|
mem_put(ctx, ptr, size, flags);
|
1998-08-17 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
1999-01-14 19:52:52 +00:00
|
|
|
/*
|
|
|
|
* Other useful things.
|
|
|
|
*/
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
char *
|
2021-02-04 20:19:09 +01:00
|
|
|
isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) {
|
2021-05-12 21:16:17 +02:00
|
|
|
size_t len;
|
|
|
|
char *ns = NULL;
|
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_CONTEXT(mctx));
|
2020-02-01 17:59:19 +01:00
|
|
|
REQUIRE(s != NULL);
|
|
|
|
|
2017-09-14 18:11:56 +10:00
|
|
|
len = strlen(s) + 1;
|
1998-12-30 20:17:02 +00:00
|
|
|
|
2022-06-03 12:23:49 +02:00
|
|
|
ns = isc__mem_allocate(mctx, len, 0 FLARG_PASS);
|
2000-02-26 19:59:30 +00:00
|
|
|
|
2021-06-10 10:18:24 +02:00
|
|
|
strlcpy(ns, s, len);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2000-07-26 19:06:20 +00:00
|
|
|
return ns;
|
2000-02-26 19:59:30 +00:00
|
|
|
}
|
|
|
|
|
2020-10-26 14:17:05 +01:00
|
|
|
char *
|
2021-02-04 20:19:09 +01:00
|
|
|
isc__mem_strndup(isc_mem_t *mctx, const char *s, size_t size FLARG) {
|
2021-05-12 21:16:17 +02:00
|
|
|
size_t len;
|
|
|
|
char *ns = NULL;
|
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_CONTEXT(mctx));
|
2020-10-26 14:17:05 +01:00
|
|
|
REQUIRE(s != NULL);
|
2021-06-10 10:18:24 +02:00
|
|
|
REQUIRE(size != 0);
|
2020-10-26 14:17:05 +01:00
|
|
|
|
|
|
|
len = strlen(s) + 1;
|
|
|
|
if (len > size) {
|
|
|
|
len = size;
|
|
|
|
}
|
|
|
|
|
2022-06-03 12:23:49 +02:00
|
|
|
ns = isc__mem_allocate(mctx, len, 0 FLARG_PASS);
|
2020-10-26 14:17:05 +01:00
|
|
|
|
2021-06-10 10:18:24 +02:00
|
|
|
strlcpy(ns, s, len);
|
2020-10-26 14:17:05 +01:00
|
|
|
|
|
|
|
return ns;
|
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
2021-02-04 20:19:09 +01:00
|
|
|
isc_mem_setdestroycheck(isc_mem_t *ctx, bool flag) {
|
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXLOCK(ctx);
|
1999-10-02 21:20:03 +00:00
|
|
|
|
2000-04-12 01:24:17 +00:00
|
|
|
ctx->checkfree = flag;
|
1999-10-02 21:20:03 +00:00
|
|
|
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXUNLOCK(ctx);
|
2000-04-12 01:24:17 +00:00
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
size_t
|
2021-02-04 20:19:09 +01:00
|
|
|
isc_mem_inuse(isc_mem_t *ctx) {
|
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
2020-02-01 17:59:19 +01:00
|
|
|
|
2025-06-04 18:14:23 +02:00
|
|
|
int_fast64_t inuse = 0;
|
|
|
|
|
|
|
|
for (ssize_t i = -1; i < isc_tid_count(); i++) {
|
|
|
|
inuse += atomic_load_relaxed(&ctx->stat[i].inuse);
|
|
|
|
}
|
|
|
|
INSIST(inuse >= 0);
|
|
|
|
|
|
|
|
return (size_t)inuse;
|
2000-04-12 01:24:17 +00:00
|
|
|
}
|
|
|
|
|
2021-07-22 06:14:32 +02:00
|
|
|
void
|
|
|
|
isc_mem_clearwater(isc_mem_t *mctx) {
|
2023-11-29 09:01:56 +01:00
|
|
|
isc_mem_setwater(mctx, 0, 0);
|
2021-07-22 06:14:32 +02:00
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
2023-11-29 09:01:56 +01:00
|
|
|
isc_mem_setwater(isc_mem_t *ctx, size_t hiwater, size_t lowater) {
|
2021-05-12 21:16:17 +02:00
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
|
|
|
REQUIRE(hiwater >= lowater);
|
2006-12-07 06:27:34 +00:00
|
|
|
|
2023-01-19 12:10:28 +01:00
|
|
|
atomic_store_release(&ctx->hi_water, hiwater);
|
|
|
|
atomic_store_release(&ctx->lo_water, lowater);
|
2021-07-07 16:05:48 +02:00
|
|
|
|
2023-11-29 09:01:56 +01:00
|
|
|
return;
|
2000-08-31 12:15:17 +00:00
|
|
|
}
|
|
|
|
|
2021-02-04 21:56:49 +01:00
|
|
|
bool
|
2021-02-04 20:19:09 +01:00
|
|
|
isc_mem_isovermem(isc_mem_t *ctx) {
|
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
2010-08-11 23:11:45 +00:00
|
|
|
|
2025-06-04 18:14:23 +02:00
|
|
|
int32_t tid = isc_tid();
|
|
|
|
|
|
|
|
bool is_overmem = atomic_load_relaxed(&ctx->stat[tid].is_overmem);
|
2023-11-29 09:01:56 +01:00
|
|
|
|
|
|
|
if (!is_overmem) {
|
|
|
|
/* We are not overmem, check whether we should be? */
|
|
|
|
size_t hiwater = atomic_load_relaxed(&ctx->hi_water);
|
|
|
|
if (hiwater == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2025-06-04 18:14:23 +02:00
|
|
|
size_t inuse = isc_mem_inuse(ctx);
|
2023-11-29 09:01:56 +01:00
|
|
|
if (inuse <= hiwater) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2025-07-24 08:06:04 +02:00
|
|
|
if ((ctx->debugging & ISC_MEM_DEBUGUSAGE) != 0) {
|
2023-11-29 09:01:56 +01:00
|
|
|
fprintf(stderr,
|
2025-06-23 07:48:36 +02:00
|
|
|
"overmem %s mctx %p inuse %zu hi_water %zu\n",
|
|
|
|
ctx->name, ctx, inuse, hiwater);
|
2023-11-29 09:01:56 +01:00
|
|
|
}
|
|
|
|
|
2025-06-04 18:14:23 +02:00
|
|
|
atomic_store_relaxed(&ctx->stat[tid].is_overmem, true);
|
2023-11-29 09:01:56 +01:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
/* We are overmem, check whether we should not be? */
|
|
|
|
size_t lowater = atomic_load_relaxed(&ctx->lo_water);
|
|
|
|
if (lowater == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2025-06-04 18:14:23 +02:00
|
|
|
size_t inuse = isc_mem_inuse(ctx);
|
2023-11-29 09:01:56 +01:00
|
|
|
if (inuse >= lowater) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2025-07-24 08:06:04 +02:00
|
|
|
if ((ctx->debugging & ISC_MEM_DEBUGUSAGE) != 0) {
|
2023-11-29 09:01:56 +01:00
|
|
|
fprintf(stderr,
|
2025-06-23 07:48:36 +02:00
|
|
|
"overmem %s mctx %p inuse %zu lo_water %zu\n",
|
|
|
|
ctx->name, ctx, inuse, lowater);
|
2023-11-29 09:01:56 +01:00
|
|
|
}
|
2025-06-04 18:14:23 +02:00
|
|
|
atomic_store_relaxed(&ctx->stat[tid].is_overmem, false);
|
2023-11-29 09:01:56 +01:00
|
|
|
return false;
|
|
|
|
}
|
2010-08-11 22:54:58 +00:00
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
const char *
|
2021-02-04 20:19:09 +01:00
|
|
|
isc_mem_getname(isc_mem_t *ctx) {
|
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
2008-03-31 05:00:30 +00:00
|
|
|
|
2013-04-11 17:07:50 +10:00
|
|
|
if (ctx->name[0] == 0) {
|
2013-04-10 13:49:57 -07:00
|
|
|
return "";
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-04-10 13:49:57 -07:00
|
|
|
|
2008-03-31 05:00:30 +00:00
|
|
|
return ctx->name;
|
|
|
|
}
|
|
|
|
|
1999-06-08 02:38:30 +00:00
|
|
|
/*
|
|
|
|
* Memory pool stuff
|
|
|
|
*/
|
|
|
|
|
2020-02-02 08:39:45 +01:00
|
|
|
void
|
2021-07-09 14:24:33 +03:00
|
|
|
isc__mempool_create(isc_mem_t *restrict mctx, const size_t element_size,
|
2025-05-28 23:00:24 +02:00
|
|
|
const char *name, isc_mempool_t **restrict mpctxp FLARG) {
|
2021-07-09 14:24:33 +03:00
|
|
|
isc_mempool_t *restrict mpctx = NULL;
|
|
|
|
size_t size = element_size;
|
2021-05-12 21:16:17 +02:00
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_CONTEXT(mctx));
|
2003-07-25 00:01:16 +00:00
|
|
|
REQUIRE(size > 0U);
|
1999-06-08 02:38:30 +00:00
|
|
|
REQUIRE(mpctxp != NULL && *mpctxp == NULL);
|
2025-05-28 23:00:24 +02:00
|
|
|
REQUIRE(name != NULL);
|
1999-06-08 02:38:30 +00:00
|
|
|
|
2018-08-14 17:13:20 +10:00
|
|
|
/*
|
|
|
|
* Mempools are stored as a linked list of element.
|
|
|
|
*/
|
|
|
|
if (size < sizeof(element)) {
|
|
|
|
size = sizeof(element);
|
|
|
|
}
|
2021-02-04 21:56:49 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate space for this pool, initialize values, and if all
|
|
|
|
* works well, attach to the memory context.
|
|
|
|
*/
|
|
|
|
mpctx = isc_mem_get(mctx, sizeof(isc_mempool_t));
|
|
|
|
|
|
|
|
*mpctx = (isc_mempool_t){
|
|
|
|
.size = size,
|
2021-07-09 14:01:22 +03:00
|
|
|
.freemax = 1,
|
|
|
|
.fillcount = 1,
|
2025-05-28 23:00:24 +02:00
|
|
|
.name = strdup(name),
|
2021-02-04 21:56:49 +01:00
|
|
|
};
|
|
|
|
|
2021-05-11 19:54:05 +02:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2022-09-23 13:49:31 +02:00
|
|
|
if ((mctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
|
2024-09-09 13:59:43 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
"create pool %p func %s file %s line %u mctx %p\n",
|
|
|
|
mpctx, func, file, line, mctx);
|
2021-05-11 19:54:05 +02:00
|
|
|
}
|
|
|
|
#endif /* ISC_MEM_TRACKLINES */
|
|
|
|
|
2022-08-31 12:30:38 +00:00
|
|
|
isc_mem_attach(mctx, &mpctx->mctx);
|
|
|
|
mpctx->magic = MEMPOOL_MAGIC;
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
*mpctxp = (isc_mempool_t *)mpctx;
|
1999-06-08 02:38:30 +00:00
|
|
|
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXLOCK(mctx);
|
2000-12-07 20:15:58 +00:00
|
|
|
ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
|
2008-03-31 05:00:30 +00:00
|
|
|
mctx->poolcnt++;
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXUNLOCK(mctx);
|
1999-06-08 02:38:30 +00:00
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
2021-07-09 14:24:33 +03:00
|
|
|
isc__mempool_destroy(isc_mempool_t **restrict mpctxp FLARG) {
|
|
|
|
isc_mempool_t *restrict mpctx = NULL;
|
2021-05-12 21:16:17 +02:00
|
|
|
isc_mem_t *mctx = NULL;
|
2021-07-09 14:24:33 +03:00
|
|
|
element *restrict item = NULL;
|
2021-05-12 21:16:17 +02:00
|
|
|
|
2020-02-01 17:59:19 +01:00
|
|
|
REQUIRE(mpctxp != NULL);
|
|
|
|
REQUIRE(VALID_MEMPOOL(*mpctxp));
|
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
mpctx = *mpctxp;
|
|
|
|
*mpctxp = NULL;
|
2021-05-11 19:54:05 +02:00
|
|
|
|
2021-05-12 21:16:17 +02:00
|
|
|
mctx = mpctx->mctx;
|
|
|
|
|
2021-05-11 19:54:05 +02:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2022-09-23 13:49:31 +02:00
|
|
|
if ((mctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
|
2024-09-09 13:59:43 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
"destroy pool %p func %s file %s line %u mctx %p\n",
|
|
|
|
mpctx, func, file, line, mctx);
|
2021-05-11 19:54:05 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-07-09 14:01:22 +03:00
|
|
|
if (mpctx->allocated > 0) {
|
2022-10-14 17:37:47 +01:00
|
|
|
UNEXPECTED_ERROR("mempool %s leaked memory", mpctx->name);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2021-07-09 14:01:22 +03:00
|
|
|
REQUIRE(mpctx->allocated == 0);
|
1999-06-08 02:38:30 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Return any items on the free list
|
|
|
|
*/
|
2001-01-25 01:18:00 +00:00
|
|
|
while (mpctx->items != NULL) {
|
2021-07-09 14:01:22 +03:00
|
|
|
INSIST(mpctx->freecount > 0);
|
|
|
|
mpctx->freecount--;
|
2021-02-04 21:56:49 +01:00
|
|
|
|
2001-01-25 01:18:00 +00:00
|
|
|
item = mpctx->items;
|
|
|
|
mpctx->items = item->next;
|
|
|
|
|
2023-01-19 12:05:44 +01:00
|
|
|
mem_putstats(mctx, mpctx->size);
|
2021-12-14 21:50:23 +01:00
|
|
|
mem_put(mctx, item, mpctx->size, 0);
|
2001-01-25 01:18:00 +00:00
|
|
|
}
|
1999-06-08 02:38:30 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove our linked list entry from the memory context.
|
|
|
|
*/
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXLOCK(mctx);
|
1999-06-08 02:38:30 +00:00
|
|
|
ISC_LIST_UNLINK(mctx->pools, mpctx, link);
|
2008-03-31 05:00:30 +00:00
|
|
|
mctx->poolcnt--;
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXUNLOCK(mctx);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2025-05-28 23:00:24 +02:00
|
|
|
free(mpctx->name);
|
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
mpctx->magic = 0;
|
1999-06-08 02:38:30 +00:00
|
|
|
|
2022-08-31 12:30:38 +00:00
|
|
|
isc_mem_putanddetach(&mpctx->mctx, mpctx, sizeof(isc_mempool_t));
|
1999-09-15 17:47:08 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 11:08:34 +01:00
|
|
|
void *
|
2021-07-09 14:24:33 +03:00
|
|
|
isc__mempool_get(isc_mempool_t *restrict mpctx FLARG) {
|
|
|
|
element *restrict item = NULL;
|
2021-02-25 11:08:34 +01:00
|
|
|
|
|
|
|
REQUIRE(VALID_MEMPOOL(mpctx));
|
|
|
|
|
2021-07-09 14:01:22 +03:00
|
|
|
mpctx->allocated++;
|
1999-06-08 02:38:30 +00:00
|
|
|
|
2021-10-14 10:33:24 +02:00
|
|
|
if (mpctx->items == NULL) {
|
2021-02-04 21:56:49 +01:00
|
|
|
isc_mem_t *mctx = mpctx->mctx;
|
2021-12-15 12:07:22 +01:00
|
|
|
#if !__SANITIZE_ADDRESS__
|
2021-07-09 14:01:22 +03:00
|
|
|
const size_t fillcount = mpctx->fillcount;
|
2021-12-15 12:07:22 +01:00
|
|
|
#else
|
|
|
|
const size_t fillcount = 1;
|
|
|
|
#endif
|
2016-03-04 11:12:23 +05:30
|
|
|
/*
|
2021-12-15 12:07:22 +01:00
|
|
|
* We need to dip into the well. Fill up our free list.
|
2016-03-04 11:12:23 +05:30
|
|
|
*/
|
2021-05-11 12:18:56 +02:00
|
|
|
for (size_t i = 0; i < fillcount; i++) {
|
2021-12-14 21:50:23 +01:00
|
|
|
item = mem_get(mctx, mpctx->size, 0);
|
2021-02-04 20:11:20 +01:00
|
|
|
mem_getstats(mctx, mpctx->size);
|
2016-03-04 11:12:23 +05:30
|
|
|
item->next = mpctx->items;
|
|
|
|
mpctx->items = item;
|
2021-07-09 14:01:22 +03:00
|
|
|
mpctx->freecount++;
|
2005-06-17 02:22:45 +00:00
|
|
|
}
|
1999-06-08 02:38:30 +00:00
|
|
|
}
|
|
|
|
|
2023-01-19 16:57:18 +01:00
|
|
|
INSIST(mpctx->items != NULL);
|
1999-06-08 02:38:30 +00:00
|
|
|
item = mpctx->items;
|
2021-07-09 14:01:22 +03:00
|
|
|
|
1999-06-08 02:38:30 +00:00
|
|
|
mpctx->items = item->next;
|
2021-02-04 21:56:49 +01:00
|
|
|
|
2021-07-09 14:01:22 +03:00
|
|
|
INSIST(mpctx->freecount > 0);
|
|
|
|
mpctx->freecount--;
|
|
|
|
mpctx->gets++;
|
2021-02-22 08:44:31 +11:00
|
|
|
|
2024-09-09 13:59:43 +02:00
|
|
|
ADD_TRACE(mpctx->mctx, item, mpctx->size, func, file, line);
|
1999-09-15 17:47:08 +00:00
|
|
|
|
1999-06-08 02:38:30 +00:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
2012-11-02 16:02:15 +11:00
|
|
|
/* coverity[+free : arg-1] */
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
2021-07-09 14:24:33 +03:00
|
|
|
isc__mempool_put(isc_mempool_t *restrict mpctx, void *mem FLARG) {
|
|
|
|
element *restrict item = NULL;
|
2021-02-25 11:08:34 +01:00
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_MEMPOOL(mpctx));
|
1999-06-08 02:38:30 +00:00
|
|
|
REQUIRE(mem != NULL);
|
|
|
|
|
2021-02-04 20:19:09 +01:00
|
|
|
isc_mem_t *mctx = mpctx->mctx;
|
2021-07-09 14:01:22 +03:00
|
|
|
const size_t freecount = mpctx->freecount;
|
2021-12-15 12:07:22 +01:00
|
|
|
#if !__SANITIZE_ADDRESS__
|
2021-07-09 14:01:22 +03:00
|
|
|
const size_t freemax = mpctx->freemax;
|
2021-12-15 12:07:22 +01:00
|
|
|
#else
|
|
|
|
const size_t freemax = 0;
|
|
|
|
#endif
|
1999-06-08 02:38:30 +00:00
|
|
|
|
2021-07-09 14:01:22 +03:00
|
|
|
INSIST(mpctx->allocated > 0);
|
|
|
|
mpctx->allocated--;
|
1999-06-08 02:38:30 +00:00
|
|
|
|
2024-09-09 13:59:43 +02:00
|
|
|
DELETE_TRACE(mctx, mem, mpctx->size, func, file, line);
|
2000-07-26 19:06:20 +00:00
|
|
|
|
1999-06-08 02:38:30 +00:00
|
|
|
/*
|
|
|
|
* If our free list is full, return this to the mctx directly.
|
|
|
|
*/
|
2021-02-04 21:56:49 +01:00
|
|
|
if (freecount >= freemax) {
|
2023-01-19 12:05:44 +01:00
|
|
|
mem_putstats(mctx, mpctx->size);
|
2021-12-14 21:50:23 +01:00
|
|
|
mem_put(mctx, mem, mpctx->size, 0);
|
1999-06-08 02:38:30 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise, attach it to our free list and bump the counter.
|
|
|
|
*/
|
|
|
|
item = (element *)mem;
|
|
|
|
item->next = mpctx->items;
|
|
|
|
mpctx->items = item;
|
2021-07-09 14:01:22 +03:00
|
|
|
mpctx->freecount++;
|
1999-06-08 02:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Quotas
|
|
|
|
*/
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
2021-07-09 14:24:33 +03:00
|
|
|
isc_mempool_setfreemax(isc_mempool_t *restrict mpctx,
|
|
|
|
const unsigned int limit) {
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_MEMPOOL(mpctx));
|
2021-07-09 14:01:22 +03:00
|
|
|
mpctx->freemax = limit;
|
1999-06-08 02:38:30 +00:00
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
unsigned int
|
2021-07-09 14:24:33 +03:00
|
|
|
isc_mempool_getfreemax(isc_mempool_t *restrict mpctx) {
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_MEMPOOL(mpctx));
|
2020-02-01 17:59:19 +01:00
|
|
|
|
2021-07-09 14:01:22 +03:00
|
|
|
return mpctx->freemax;
|
1999-06-08 02:38:30 +00:00
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
unsigned int
|
2021-07-09 14:24:33 +03:00
|
|
|
isc_mempool_getfreecount(isc_mempool_t *restrict mpctx) {
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_MEMPOOL(mpctx));
|
2020-02-01 17:59:19 +01:00
|
|
|
|
2021-07-09 14:01:22 +03:00
|
|
|
return mpctx->freecount;
|
1999-06-08 02:38:30 +00:00
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
unsigned int
|
2021-07-09 14:24:33 +03:00
|
|
|
isc_mempool_getallocated(isc_mempool_t *restrict mpctx) {
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_MEMPOOL(mpctx));
|
2020-02-01 17:59:19 +01:00
|
|
|
|
2021-07-09 14:01:22 +03:00
|
|
|
return mpctx->allocated;
|
1999-06-08 02:38:30 +00:00
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
2021-07-09 14:24:33 +03:00
|
|
|
isc_mempool_setfillcount(isc_mempool_t *restrict mpctx,
|
|
|
|
unsigned int const limit) {
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_MEMPOOL(mpctx));
|
1999-06-08 02:38:30 +00:00
|
|
|
REQUIRE(limit > 0);
|
2020-02-01 17:59:19 +01:00
|
|
|
|
2021-07-09 14:01:22 +03:00
|
|
|
mpctx->fillcount = limit;
|
1999-06-08 02:38:30 +00:00
|
|
|
}
|
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
unsigned int
|
2021-07-09 14:24:33 +03:00
|
|
|
isc_mempool_getfillcount(isc_mempool_t *restrict mpctx) {
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_MEMPOOL(mpctx));
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2021-07-09 14:01:22 +03:00
|
|
|
return mpctx->fillcount;
|
1999-06-08 02:38:30 +00:00
|
|
|
}
|
2006-01-04 03:16:47 +00:00
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
/*
|
|
|
|
* Requires contextslock to be held by caller.
|
|
|
|
*/
|
2021-02-04 23:10:39 +01:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2017-09-08 13:39:09 -07:00
|
|
|
static void
|
|
|
|
print_contexts(FILE *file) {
|
2025-03-20 22:25:56 -07:00
|
|
|
ISC_LIST_FOREACH(contexts, ctx, link) {
|
2018-10-03 07:59:18 +10:00
|
|
|
fprintf(file, "context: %p (%s): %" PRIuFAST32 " references\n",
|
2017-09-08 13:39:09 -07:00
|
|
|
ctx, ctx->name[0] == 0 ? "<unknown>" : ctx->name,
|
2018-05-24 14:43:25 +02:00
|
|
|
isc_refcount_current(&ctx->references));
|
2017-09-08 13:39:09 -07:00
|
|
|
print_active(ctx, file);
|
|
|
|
}
|
|
|
|
fflush(file);
|
|
|
|
}
|
2021-02-04 23:10:39 +01:00
|
|
|
#endif
|
2017-09-08 13:39:09 -07:00
|
|
|
|
2022-03-08 23:55:10 +01:00
|
|
|
static atomic_uintptr_t checkdestroyed = 0;
|
2021-02-09 17:44:40 +01:00
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
void
|
|
|
|
isc_mem_checkdestroyed(FILE *file) {
|
2021-02-09 17:44:40 +01:00
|
|
|
atomic_store_release(&checkdestroyed, (uintptr_t)file);
|
|
|
|
}
|
2006-01-04 03:16:47 +00:00
|
|
|
|
2021-02-09 17:44:40 +01:00
|
|
|
void
|
|
|
|
isc__mem_checkdestroyed(void) {
|
|
|
|
FILE *file = (FILE *)atomic_load_acquire(&checkdestroyed);
|
|
|
|
|
|
|
|
if (file == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2006-01-04 03:16:47 +00:00
|
|
|
|
2015-01-20 13:29:18 -08:00
|
|
|
LOCK(&contextslock);
|
2017-04-22 08:25:10 +05:30
|
|
|
if (!ISC_LIST_EMPTY(contexts)) {
|
2006-01-04 03:16:47 +00:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2025-07-24 08:06:04 +02:00
|
|
|
if ((mem_debugging & TRACE_OR_RECORD) != 0) {
|
2017-09-08 13:39:09 -07:00
|
|
|
print_contexts(file);
|
2006-01-04 03:16:47 +00:00
|
|
|
}
|
|
|
|
#endif /* if ISC_MEM_TRACKLINES */
|
2021-10-11 12:50:17 +02:00
|
|
|
UNREACHABLE();
|
2006-01-04 03:16:47 +00:00
|
|
|
}
|
2015-01-20 13:29:18 -08:00
|
|
|
UNLOCK(&contextslock);
|
2006-01-04 03:16:47 +00:00
|
|
|
}
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2013-04-10 13:49:57 -07:00
|
|
|
unsigned int
|
2021-02-04 20:19:09 +01:00
|
|
|
isc_mem_references(isc_mem_t *ctx) {
|
2018-05-24 14:43:25 +02:00
|
|
|
return isc_refcount_current(&ctx->references);
|
2008-01-02 05:03:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-13 14:24:50 -07:00
|
|
|
#ifdef HAVE_LIBXML2
|
2012-11-01 10:22:11 +11:00
|
|
|
#define TRY0(a) \
|
|
|
|
do { \
|
|
|
|
xmlrc = (a); \
|
|
|
|
if (xmlrc < 0) \
|
|
|
|
goto error; \
|
|
|
|
} while (0)
|
|
|
|
static int
|
2023-01-19 16:57:18 +01:00
|
|
|
xml_renderctx(isc_mem_t *ctx, size_t *inuse, xmlTextWriterPtr writer) {
|
2007-02-13 02:49:08 +00:00
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
|
|
|
|
2020-02-01 17:59:19 +01:00
|
|
|
int xmlrc;
|
|
|
|
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXLOCK(ctx);
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"));
|
|
|
|
|
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"));
|
|
|
|
TRY0(xmlTextWriterWriteFormatString(writer, "%p", ctx));
|
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* id */
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2008-03-31 05:00:30 +00:00
|
|
|
if (ctx->name[0] != 0) {
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
|
|
|
|
TRY0(xmlTextWriterWriteFormatString(writer, "%s", ctx->name));
|
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* name */
|
2008-03-31 05:00:30 +00:00
|
|
|
}
|
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"));
|
2018-10-03 07:59:18 +10:00
|
|
|
TRY0(xmlTextWriterWriteFormatString(
|
|
|
|
writer, "%" PRIuFAST32,
|
2018-05-24 14:43:25 +02:00
|
|
|
isc_refcount_current(&ctx->references)));
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* references */
|
2008-03-31 05:00:30 +00:00
|
|
|
|
2023-01-19 16:57:18 +01:00
|
|
|
*inuse += isc_mem_inuse(ctx);
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"));
|
|
|
|
TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
|
2021-02-04 21:56:49 +01:00
|
|
|
(uint64_t)isc_mem_inuse(ctx)));
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* inuse */
|
|
|
|
|
2023-01-19 16:57:18 +01:00
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "malloced"));
|
|
|
|
TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
|
|
|
|
(uint64_t)isc_mem_inuse(ctx)));
|
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* malloced */
|
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"));
|
|
|
|
TRY0(xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt));
|
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* pools */
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"));
|
2021-02-04 21:56:49 +01:00
|
|
|
TRY0(xmlTextWriterWriteFormatString(
|
|
|
|
writer, "%" PRIu64 "",
|
2021-07-22 06:14:32 +02:00
|
|
|
(uint64_t)atomic_load_relaxed(&ctx->hi_water)));
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* hiwater */
|
|
|
|
|
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"));
|
2021-02-04 21:56:49 +01:00
|
|
|
TRY0(xmlTextWriterWriteFormatString(
|
|
|
|
writer, "%" PRIu64 "",
|
2021-07-22 06:14:32 +02:00
|
|
|
(uint64_t)atomic_load_relaxed(&ctx->lo_water)));
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* lowater */
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* context */
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
error:
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXUNLOCK(ctx);
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
return xmlrc;
|
2008-03-31 05:00:30 +00:00
|
|
|
}
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
int
|
2019-06-24 14:25:55 +02:00
|
|
|
isc_mem_renderxml(void *writer0) {
|
2023-01-19 16:57:18 +01:00
|
|
|
size_t inuse = 0;
|
2012-11-01 10:22:11 +11:00
|
|
|
int xmlrc;
|
2019-06-24 14:25:55 +02:00
|
|
|
xmlTextWriterPtr writer = (xmlTextWriterPtr)writer0;
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"));
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2015-01-20 13:29:18 -08:00
|
|
|
LOCK(&contextslock);
|
2025-03-20 22:25:56 -07:00
|
|
|
ISC_LIST_FOREACH(contexts, ctx, link) {
|
2023-01-19 16:57:18 +01:00
|
|
|
xmlrc = xml_renderctx(ctx, &inuse, writer);
|
2012-11-01 10:22:11 +11:00
|
|
|
if (xmlrc < 0) {
|
2015-01-20 13:29:18 -08:00
|
|
|
UNLOCK(&contextslock);
|
2012-11-01 10:22:11 +11:00
|
|
|
goto error;
|
|
|
|
}
|
2008-03-31 05:00:30 +00:00
|
|
|
}
|
2015-01-20 13:29:18 -08:00
|
|
|
UNLOCK(&contextslock);
|
2007-02-13 02:49:08 +00:00
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* contexts */
|
|
|
|
|
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"));
|
|
|
|
|
2023-01-19 16:57:18 +01:00
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "Malloced"));
|
|
|
|
TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
|
|
|
|
(uint64_t)inuse));
|
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* malloced */
|
|
|
|
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"));
|
|
|
|
TRY0(xmlTextWriterWriteFormatString(writer, "%" PRIu64 "",
|
2023-01-19 16:57:18 +01:00
|
|
|
(uint64_t)inuse));
|
2012-11-01 10:22:11 +11:00
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* InUse */
|
|
|
|
|
|
|
|
TRY0(xmlTextWriterEndElement(writer)); /* summary */
|
|
|
|
error:
|
|
|
|
return xmlrc;
|
2007-02-13 02:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAVE_LIBXML2 */
|
2013-03-13 14:24:50 -07:00
|
|
|
|
2019-02-06 11:56:42 +01:00
|
|
|
#ifdef HAVE_JSON_C
|
2018-11-18 09:15:46 +01:00
|
|
|
#define CHECKMEM(m) RUNTIME_CHECK(m != NULL)
|
2013-03-13 14:24:50 -07:00
|
|
|
|
|
|
|
static isc_result_t
|
2023-01-19 16:57:18 +01:00
|
|
|
json_renderctx(isc_mem_t *ctx, size_t *inuse, json_object *array) {
|
2013-03-13 14:24:50 -07:00
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
|
|
|
REQUIRE(array != NULL);
|
|
|
|
|
2020-02-01 17:59:19 +01:00
|
|
|
json_object *ctxobj, *obj;
|
|
|
|
char buf[1024];
|
|
|
|
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXLOCK(ctx);
|
2013-03-13 14:24:50 -07:00
|
|
|
|
2023-01-19 16:57:18 +01:00
|
|
|
*inuse += isc_mem_inuse(ctx);
|
2013-03-13 14:24:50 -07:00
|
|
|
|
|
|
|
ctxobj = json_object_new_object();
|
|
|
|
CHECKMEM(ctxobj);
|
|
|
|
|
2017-10-03 14:54:19 +11:00
|
|
|
snprintf(buf, sizeof(buf), "%p", ctx);
|
2013-03-13 14:24:50 -07:00
|
|
|
obj = json_object_new_string(buf);
|
|
|
|
CHECKMEM(obj);
|
|
|
|
json_object_object_add(ctxobj, "id", obj);
|
|
|
|
|
|
|
|
if (ctx->name[0] != 0) {
|
|
|
|
obj = json_object_new_string(ctx->name);
|
|
|
|
CHECKMEM(obj);
|
|
|
|
json_object_object_add(ctxobj, "name", obj);
|
|
|
|
}
|
|
|
|
|
2018-05-24 14:43:25 +02:00
|
|
|
obj = json_object_new_int64(isc_refcount_current(&ctx->references));
|
2013-03-13 14:24:50 -07:00
|
|
|
CHECKMEM(obj);
|
|
|
|
json_object_object_add(ctxobj, "references", obj);
|
|
|
|
|
2023-01-19 16:57:18 +01:00
|
|
|
obj = json_object_new_int64(isc_mem_inuse(ctx));
|
|
|
|
CHECKMEM(obj);
|
|
|
|
json_object_object_add(ctxobj, "malloced", obj);
|
|
|
|
|
2021-02-04 21:56:49 +01:00
|
|
|
obj = json_object_new_int64(isc_mem_inuse(ctx));
|
2013-03-13 14:24:50 -07:00
|
|
|
CHECKMEM(obj);
|
|
|
|
json_object_object_add(ctxobj, "inuse", obj);
|
|
|
|
|
|
|
|
obj = json_object_new_int64(ctx->poolcnt);
|
|
|
|
CHECKMEM(obj);
|
|
|
|
json_object_object_add(ctxobj, "pools", obj);
|
|
|
|
|
2021-07-22 06:14:32 +02:00
|
|
|
obj = json_object_new_int64(atomic_load_relaxed(&ctx->hi_water));
|
2013-03-13 14:24:50 -07:00
|
|
|
CHECKMEM(obj);
|
|
|
|
json_object_object_add(ctxobj, "hiwater", obj);
|
|
|
|
|
2021-07-22 06:14:32 +02:00
|
|
|
obj = json_object_new_int64(atomic_load_relaxed(&ctx->lo_water));
|
2013-03-13 14:24:50 -07:00
|
|
|
CHECKMEM(obj);
|
|
|
|
json_object_object_add(ctxobj, "lowater", obj);
|
|
|
|
|
2019-09-06 12:46:57 +02:00
|
|
|
MCTXUNLOCK(ctx);
|
2013-03-13 14:24:50 -07:00
|
|
|
json_object_array_add(array, ctxobj);
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2019-06-24 12:21:47 +02:00
|
|
|
isc_mem_renderjson(void *memobj0) {
|
2013-03-13 14:24:50 -07:00
|
|
|
isc_result_t result = ISC_R_SUCCESS;
|
2023-01-19 16:57:18 +01:00
|
|
|
size_t inuse = 0;
|
2013-03-13 14:24:50 -07:00
|
|
|
json_object *ctxarray, *obj;
|
2019-06-24 12:21:47 +02:00
|
|
|
json_object *memobj = (json_object *)memobj0;
|
2013-03-13 14:24:50 -07:00
|
|
|
|
|
|
|
ctxarray = json_object_new_array();
|
|
|
|
CHECKMEM(ctxarray);
|
|
|
|
|
2015-01-20 13:29:18 -08:00
|
|
|
LOCK(&contextslock);
|
2025-03-20 22:25:56 -07:00
|
|
|
ISC_LIST_FOREACH(contexts, ctx, link) {
|
2023-01-19 16:57:18 +01:00
|
|
|
result = json_renderctx(ctx, &inuse, ctxarray);
|
2013-03-13 14:24:50 -07:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2015-01-20 13:29:18 -08:00
|
|
|
UNLOCK(&contextslock);
|
2013-03-13 14:24:50 -07:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2015-01-20 13:29:18 -08:00
|
|
|
UNLOCK(&contextslock);
|
2013-03-13 14:24:50 -07:00
|
|
|
|
2023-01-19 16:57:18 +01:00
|
|
|
obj = json_object_new_int64(inuse);
|
2013-03-13 14:24:50 -07:00
|
|
|
CHECKMEM(obj);
|
|
|
|
json_object_object_add(memobj, "InUse", obj);
|
|
|
|
|
2023-01-19 16:57:18 +01:00
|
|
|
obj = json_object_new_int64(inuse);
|
|
|
|
CHECKMEM(obj);
|
|
|
|
json_object_object_add(memobj, "Malloced", obj);
|
|
|
|
|
2013-03-13 14:24:50 -07:00
|
|
|
json_object_object_add(memobj, "contexts", ctxarray);
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (ctxarray != NULL) {
|
|
|
|
json_object_put(ctxarray);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-03-13 14:24:50 -07:00
|
|
|
return result;
|
|
|
|
}
|
2019-02-06 11:56:42 +01:00
|
|
|
#endif /* HAVE_JSON_C */
|
2013-04-10 13:49:57 -07:00
|
|
|
|
2019-09-05 18:40:57 +02:00
|
|
|
void
|
2025-02-21 12:45:08 +01:00
|
|
|
isc__mem_create(const char *name, isc_mem_t **mctxp FLARG) {
|
2025-07-24 08:06:04 +02:00
|
|
|
mem_create(name, mctxp, mem_debugging, isc_mem_defaultflags, 0);
|
2021-05-11 12:18:56 +02:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2025-07-24 08:06:04 +02:00
|
|
|
if ((mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
|
2024-09-09 13:59:43 +02:00
|
|
|
fprintf(stderr, "create mctx %p func %s file %s line %u\n",
|
|
|
|
*mctxp, func, file, line);
|
2021-05-11 12:18:56 +02:00
|
|
|
}
|
|
|
|
#endif /* ISC_MEM_TRACKLINES */
|
2013-04-10 13:49:57 -07:00
|
|
|
}
|
|
|
|
|
2018-10-03 19:04:46 -07:00
|
|
|
void
|
2021-02-04 20:19:09 +01:00
|
|
|
isc__mem_printactive(isc_mem_t *ctx, FILE *file) {
|
2018-10-03 19:04:46 -07:00
|
|
|
#if ISC_MEM_TRACKLINES
|
2021-02-04 20:19:09 +01:00
|
|
|
REQUIRE(VALID_CONTEXT(ctx));
|
2018-10-03 19:04:46 -07:00
|
|
|
REQUIRE(file != NULL);
|
|
|
|
|
|
|
|
print_active(ctx, file);
|
|
|
|
#else /* if ISC_MEM_TRACKLINES */
|
2021-02-04 20:19:09 +01:00
|
|
|
UNUSED(ctx);
|
2018-10-03 19:04:46 -07:00
|
|
|
UNUSED(file);
|
|
|
|
#endif /* if ISC_MEM_TRACKLINES */
|
2013-04-10 13:49:57 -07:00
|
|
|
}
|