Merge branch '3559-provide-custom-isc_mem-based-allocators-for-external-libraries' into 'main'

Use custom isc_mem based allocator for libuv, OpenSSL, and libxml2

Closes #3559

See merge request isc-projects/bind9!6807
This commit is contained in:
Ondřej Surý 2022-09-27 15:55:09 +00:00
commit 1f670f4b69
18 changed files with 422 additions and 101 deletions

View file

@ -230,6 +230,7 @@ stages:
--with-cmocka
--with-libxml2
--with-json-c
--enable-leak-detection
$EXTRA_CONFIGURE
|| (test -s config.log && cat config.log; exit 1)
@ -757,7 +758,7 @@ gcc:sid:amd64:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -O3 -DOPENSSL_API_COMPAT=10100"
# For the jemalloc ./configure option, see https://gitlab.isc.org/isc-projects/bind9/-/issues/3444
EXTRA_CONFIGURE: "--with-libidn2 --without-lmdb --without-jemalloc ${WITH_READLINE}"
EXTRA_CONFIGURE: "--with-libidn2 --without-lmdb --without-jemalloc --disable-leak-detection ${WITH_READLINE}"
RUN_MAKE_INSTALL: 1
<<: *debian_sid_amd64_image
<<: *build_job
@ -1037,7 +1038,7 @@ clang:bullseye:amd64:
CC: ${CLANG}
CFLAGS: "${CFLAGS_COMMON} -Wenum-conversion"
# See https://gitlab.isc.org/isc-projects/bind9/-/issues/3444
EXTRA_CONFIGURE: "--without-jemalloc"
EXTRA_CONFIGURE: "--without-jemalloc --disable-leak-detection"
<<: *debian_bullseye_amd64_image
<<: *build_job

View file

@ -1,3 +1,11 @@
5987. [func] Provide custom isc_mem based allocators for libuv,
OpenSSL and libxml2 libraries that support replacing
the internal allocators. [GL #3559]
5986. [func] Make the memory context debugging options local to
the memory context and make it immutable for the memory
context lifetime. [GL #3559]
5985. [func] Bump the minimal libuv version to 1.34.0. [GL #3567]
5984. [func] 'named -V' now reports the list of supported

View file

@ -6,7 +6,8 @@ AM_CPPFLAGS += \
$(LIBISCCFG_CFLAGS) \
$(LIBIRS_CFLAGS) \
$(LIBBIND9_CFLAGS) \
$(LIBIDN2_CFLAGS)
$(LIBIDN2_CFLAGS) \
$(LIBUV_CFLAGS)
LDADD += \
libdighost.la \

View file

@ -54,8 +54,11 @@
#include <isc/string.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/tls.h>
#include <isc/types.h>
#include <isc/util.h>
#include <isc/uv.h>
#include <isc/xml.h>
#include <dns/byaddr.h>
#include <dns/fixedname.h>
@ -4701,6 +4704,14 @@ destroy_libs(void) {
}
isc_managers_destroy(&mctx, &loopmgr, &netmgr, &taskmgr);
#if ENABLE_LEAK_DETECTION
isc__tls_setdestroycheck(true);
isc__uv_setdestroycheck(true);
isc__xml_setdestroycheck(true);
#endif
isc_mem_checkdestroyed(stderr);
}
#ifdef HAVE_LIBIDN2

View file

@ -44,6 +44,7 @@
#include <isc/timer.h>
#include <isc/util.h>
#include <isc/uv.h>
#include <isc/xml.h>
#include <dns/dispatch.h>
#include <dns/dyndb.h>
@ -1471,10 +1472,6 @@ main(int argc, char *argv[]) {
(void)ProfilerStart(NULL);
#endif /* ifdef HAVE_GPERFTOOLS_PROFILER */
#ifdef HAVE_LIBXML2
xmlInitParser();
#endif /* HAVE_LIBXML2 */
/*
* Technically, this call is superfluous because on startup of the main
* program, the portable "C" locale is selected by default. This
@ -1585,6 +1582,13 @@ main(int argc, char *argv[]) {
isc_managers_destroy(&named_g_mctx, &named_g_loopmgr, &named_g_netmgr,
&named_g_taskmgr);
#if ENABLE_LEAK_DETECTION
isc__tls_setdestroycheck(true);
isc__uv_setdestroycheck(true);
isc__xml_setdestroycheck(true);
#endif
isc_mem_checkdestroyed(stderr);
named_main_setmemstats(NULL);
@ -1593,10 +1597,6 @@ main(int argc, char *argv[]) {
named_os_shutdown();
#ifdef HAVE_LIBXML2
xmlCleanupParser();
#endif /* HAVE_LIBXML2 */
#ifdef HAVE_GPERFTOOLS_PROFILER
ProfilerStop();
#endif /* ifdef HAVE_GPERFTOOLS_PROFILER */

View file

@ -1220,16 +1220,40 @@ AC_LINK_IFELSE(
)
#
# Check for __builtin_uadd_overflow
# Check for __builtin_*_overflow
#
AC_MSG_CHECKING([compiler support for __builtin_*_overflow()])
AC_MSG_CHECKING([compiler support for __builtin_add_overflow()])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <limits.h>]],
[[return (__builtin_uadd_overflow(UINT_MAX, UINT_MAX, &(unsigned int){ 0 }));]]
[[return (__builtin_add_overflow((unsigned int)UINT_MAX, (unsigned int)UINT_MAX, &(unsigned int){ 0 }));]]
)],
[AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_BUILTIN_OVERFLOW], [1], [define if the compiler supports __builtin_*_overflow().])
AC_DEFINE([HAVE_BUILTIN_ADD_OVERFLOW], [1], [define if the compiler supports __builtin_add_overflow().])
],
[AC_MSG_RESULT([no])
])
AC_MSG_CHECKING([compiler support for __builtin_sub_overflow()])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <limits.h>]],
[[return (__builtin_sub_overflow((unsigned int)0, (unsigned int)UINT_MAX, &(unsigned int){ 0 }));]]
)],
[AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_BUILTIN_SUB_OVERFLOW], [1], [define if the compiler supports __builtin_sub_overflow().])
],
[AC_MSG_RESULT([no])
])
AC_MSG_CHECKING([compiler support for __builtin_mul_overflow()])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <limits.h>]],
[[return (__builtin_mul_overflow(UINT64_C(UINT64_MAX), UINT64_C(UINT64_MAX), &(uint64_t){ 0 }));]]
)],
[AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_BUILTIN_MUL_OVERFLOW], [1], [define if the compiler supports __builtin_mul_overflow().])
],
[AC_MSG_RESULT([no])
])
@ -1395,6 +1419,16 @@ AS_IF([test "$with_jemalloc" = "no"],
AM_CONDITIONAL([HAVE_JEMALLOC], [test "$with_jemalloc" = "yes"])
#
# Check memory leaks in external libraries
#
# [pairwise: --enable-leak-detection, --disable-leak-detection]
AC_ARG_ENABLE([leak-detection],
[AS_HELP_STRING([--enable-leak-detection],[enable the memory leak detection in external libraries (libxml2, libuv, OpenSSL) (disabled by default)])],
[],[enable_leak_detection=no])
AS_CASE([$enable_leak_detection],
[yes],[AC_DEFINE([ENABLE_LEAK_DETECTION], [1], [Define to enable memory leak detection in external libraries])])
#
# was --with-tuning specified?
#

View file

@ -580,6 +580,19 @@ loops.
None of these allocation functions, including `isc_mempool_get()`, can
fail. If no memory is available for allocation, the program will abort.
The memory context can be set to check if all memory allocated via the said
memory context was freed before the memory context was destroyed by calling
`isc_mem_checkdestroyed()`. This could lead to false positives on abnormal
shutdowns, so the checking is only enabled in `dig` and `named` applications on
normal shutdown.
The memory context are normally used only for internal allocations, but several
external libraries allow replacing their allocators (namely libxml2, libuv and
OpenSSL). As there has been known memory leak in the OpenSSL when
`engine_pkcs11` is loaded, memory checking at destroy is disabled by default in
the memory contexts used for external libraries and it needs to be enabled with
a `--enable-leak-detection` autoconf option.
#### <a name="lists"></a>Lists
A set of macros are provided for creating, modifying and iterating

View file

@ -105,6 +105,7 @@ libisc_la_HEADERS = \
include/isc/utf8.h \
include/isc/util.h \
include/isc/uv.h \
include/isc/xml.h \
include/isc/work.h
libisc_la_SOURCES = \
@ -204,13 +205,13 @@ libisc_la_SOURCES = \
time.c \
timer.c \
tls.c \
tls_p.h \
tm.c \
trampoline.c \
trampoline_p.h \
url.c \
utf8.c \
uv.c \
xml.c \
work.c
libisc_la_CPPFLAGS = \

View file

@ -562,3 +562,12 @@ isc_tlsctx_cache_find(
* 'pstore' still might get initialised as there is one to many
* relation between stores and contexts.
*/
void
isc__tls_initialize(void);
void
isc__tls_shutdown(void);
void
isc__tls_setdestroycheck(bool check);

View file

@ -107,3 +107,14 @@ isc__uverr2result(int uverr, bool dolog, const char *file, unsigned int line,
})
#endif
/*
* Internal
*/
void
isc__uv_initialize(void);
void
isc__uv_shutdown(void);
void
isc__uv_setdestroycheck(bool check);

View file

@ -13,8 +13,13 @@
#pragma once
void
isc__tls_initialize(void);
#include <stdbool.h>
void
isc__tls_shutdown(void);
isc__xml_initialize(void);
void
isc__xml_shutdown(void);
void
isc__xml_setdestroycheck(bool check);

View file

@ -18,12 +18,13 @@
#include <isc/os.h>
#include <isc/tls.h>
#include <isc/util.h>
#include <isc/uv.h>
#include <isc/xml.h>
#include "config.h"
#include "mem_p.h"
#include "mutex_p.h"
#include "os_p.h"
#include "tls_p.h"
#include "trampoline_p.h"
#ifndef ISC_CONSTRUCTOR
@ -46,11 +47,15 @@ isc__initialize(void) {
isc__mem_initialize();
isc__tls_initialize();
isc__trampoline_initialize();
isc__uv_initialize();
isc__xml_initialize();
(void)isc_os_ncpus();
}
void
isc__shutdown(void) {
isc__xml_shutdown();
isc__uv_shutdown();
isc__trampoline_shutdown();
isc__tls_shutdown();
isc__mem_shutdown();

View file

@ -132,6 +132,7 @@ static uint64_t totallost;
struct isc_mem {
unsigned int magic;
unsigned int flags;
unsigned int debugging;
isc_mutex_t lock;
bool checkfree;
struct stats stats[STATS_BUCKETS + 1];
@ -184,23 +185,23 @@ struct isc_mempool {
*/
#if !ISC_MEM_TRACKLINES
#define ADD_TRACE(a, b, c, d, e)
#define DELETE_TRACE(a, b, c, d, e)
#define ADD_TRACE(mctx, ptr, size, file, line)
#define DELETE_TRACE(mctx, ptr, size, file, line)
#define ISC_MEMFUNC_SCOPE
#else /* if !ISC_MEM_TRACKLINES */
#define TRACE_OR_RECORD (ISC_MEM_DEBUGTRACE | ISC_MEM_DEBUGRECORD)
#define SHOULD_TRACE_OR_RECORD(ptr) \
((isc_mem_debugging & TRACE_OR_RECORD) != 0 && ptr != NULL)
#define SHOULD_TRACE_OR_RECORD(mctx, ptr) \
(((mctx)->debugging & TRACE_OR_RECORD) != 0 && ptr != NULL)
#define ADD_TRACE(a, b, c, d, e) \
if (SHOULD_TRACE_OR_RECORD(b)) { \
add_trace_entry(a, b, c, d, e); \
#define ADD_TRACE(mctx, ptr, size, file, line) \
if (SHOULD_TRACE_OR_RECORD(mctx, ptr)) { \
add_trace_entry(mctx, ptr, size, file, line); \
}
#define DELETE_TRACE(a, b, c, d, e) \
if (SHOULD_TRACE_OR_RECORD(b)) { \
delete_trace_entry(a, b, c, d, e); \
#define DELETE_TRACE(mctx, ptr, size, file, line) \
if (SHOULD_TRACE_OR_RECORD(mctx, ptr)) { \
delete_trace_entry(mctx, ptr, size, file, line); \
}
static void
@ -239,7 +240,7 @@ add_trace_entry(isc_mem_t *mctx, const void *ptr, size_t size FLARG) {
MCTXLOCK(mctx);
if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
if ((mctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
fprintf(stderr, "add %p size %zu file %s line %u mctx %p\n",
ptr, size, file, line, mctx);
}
@ -284,7 +285,7 @@ delete_trace_entry(isc_mem_t *mctx, const void *ptr, size_t size,
MCTXLOCK(mctx);
if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
if ((mctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
fprintf(stderr, "del %p size %zu file %s line %u mctx %p\n",
ptr, size, file, line, mctx);
}
@ -456,7 +457,7 @@ isc__mem_shutdown(void) {
}
static void
mem_create(isc_mem_t **ctxp, unsigned int flags) {
mem_create(isc_mem_t **ctxp, unsigned int debugging, unsigned int flags) {
isc_mem_t *ctx = NULL;
REQUIRE(ctxp != NULL && *ctxp == NULL);
@ -466,6 +467,7 @@ mem_create(isc_mem_t **ctxp, unsigned int flags) {
*ctx = (isc_mem_t){
.magic = MEM_MAGIC,
.debugging = debugging,
.flags = flags,
.checkfree = true,
};
@ -490,7 +492,7 @@ mem_create(isc_mem_t **ctxp, unsigned int flags) {
ISC_LIST_INIT(ctx->pools);
#if ISC_MEM_TRACKLINES
if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) {
if ((ctx->debugging & ISC_MEM_DEBUGRECORD) != 0) {
unsigned int i;
ctx->debuglist =
@ -605,7 +607,7 @@ isc__mem_detach(isc_mem_t **ctxp FLARG) {
if (isc_refcount_decrement(&ctx->references) == 1) {
isc_refcount_destroy(&ctx->references);
#if ISC_MEM_TRACKLINES
if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
if ((ctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
fprintf(stderr, "destroy mctx %p file %s line %u\n",
ctx, file, line);
}
@ -662,7 +664,7 @@ isc__mem_destroy(isc_mem_t **ctxp FLARG) {
*ctxp = NULL;
#if ISC_MEM_TRACKLINES
if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
if ((ctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
fprintf(stderr, "destroy mctx %p file %s line %u\n", ctx, file,
line);
}
@ -713,7 +715,7 @@ hi_water(isc_mem_t *ctx) {
(void)atomic_compare_exchange_strong(&ctx->maxinuse, &maxinuse,
inuse);
if ((isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) {
if ((ctx->debugging & ISC_MEM_DEBUGUSAGE) != 0) {
fprintf(stderr, "maxinuse = %lu\n",
(unsigned long)inuse);
}
@ -1189,7 +1191,7 @@ isc__mempool_create(isc_mem_t *restrict mctx, const size_t element_size,
};
#if ISC_MEM_TRACKLINES
if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
if ((mctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
fprintf(stderr, "create pool %p file %s line %u mctx %p\n",
mpctx, file, line, mctx);
}
@ -1229,7 +1231,7 @@ isc__mempool_destroy(isc_mempool_t **restrict mpctxp FLARG) {
mctx = mpctx->mctx;
#if ISC_MEM_TRACKLINES
if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
if ((mctx->debugging & ISC_MEM_DEBUGTRACE) != 0) {
fprintf(stderr, "destroy pool %p file %s line %u mctx %p\n",
mpctx, file, line, mctx);
}
@ -1747,7 +1749,7 @@ error:
void
isc__mem_create(isc_mem_t **mctxp FLARG) {
mem_create(mctxp, isc_mem_defaultflags);
mem_create(mctxp, isc_mem_debugging, isc_mem_defaultflags);
#if ISC_MEM_TRACKLINES
if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
fprintf(stderr, "create mctx %p file %s line %u\n", *mctxp,

View file

@ -194,8 +194,8 @@ isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) {
REQUIRE(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
/* Seconds */
#if HAVE_BUILTIN_OVERFLOW
if (__builtin_uadd_overflow(t->seconds, i->seconds, &result->seconds)) {
#if HAVE_BUILTIN_ADD_OVERFLOW
if (__builtin_add_overflow(t->seconds, i->seconds, &result->seconds)) {
return (ISC_R_RANGE);
}
#else
@ -225,8 +225,8 @@ isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
REQUIRE(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
/* Seconds */
#if HAVE_BUILTIN_OVERFLOW
if (__builtin_usub_overflow(t->seconds, i->seconds, &result->seconds)) {
#if HAVE_BUILTIN_SUB_OVERFLOW
if (__builtin_sub_overflow(t->seconds, i->seconds, &result->seconds)) {
return (ISC_R_RANGE);
}
#else

View file

@ -37,6 +37,7 @@
#include <isc/ht.h>
#include <isc/log.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/mutex.h>
#include <isc/mutexblock.h>
#include <isc/once.h>
@ -49,15 +50,11 @@
#include <isc/util.h>
#include "openssl_shim.h"
#include "tls_p.h"
#define COMMON_SSL_OPTIONS \
(SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)
static isc_once_t init_once = ISC_ONCE_INIT;
static isc_once_t shut_once = ISC_ONCE_INIT;
static atomic_bool init_done = false;
static atomic_bool shut_done = false;
static isc_mem_t *isc__tls_mctx = NULL;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static isc_mutex_t *locks = NULL;
@ -80,26 +77,116 @@ isc__tls_set_thread_id(CRYPTO_THREADID *id) {
}
#endif
#if !defined(LIBRESSL_VERSION_NUMBER)
/*
* This was crippled with LibreSSL, so just skip it:
* https://cvsweb.openbsd.org/src/lib/libcrypto/Attic/mem.c
*/
#if ISC_MEM_TRACKLINES
/*
* We use the internal isc__mem API here, so we can pass the file and line
* arguments passed from OpenSSL >= 1.1.0 to our memory functions for better
* tracking of the OpenSSL allocations. Without this, we would always just see
* isc__tls_{malloc,realloc,free} in the tracking output, but with this in place
* we get to see the places in the OpenSSL code where the allocations happen.
*/
static void *
isc__tls_malloc_ex(size_t size, const char *file, int line) {
return (isc__mem_allocate(isc__tls_mctx, size, file,
(unsigned int)line));
}
static void *
isc__tls_realloc_ex(void *ptr, size_t size, const char *file, int line) {
return (isc__mem_reallocate(isc__tls_mctx, ptr, size, file,
(unsigned int)line));
}
static void
tls_initialize(void) {
REQUIRE(!atomic_load(&init_done));
isc__tls_free_ex(void *ptr, const char *file, int line) {
if (ptr == NULL) {
return;
}
isc__mem_free(isc__tls_mctx, ptr, file, (unsigned int)line);
}
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
static void *
isc__tls_malloc_ex(size_t size, const char *file, int line) {
UNUSED(file);
UNUSED(line);
return (isc_mem_allocate(isc__tls_mctx, size));
}
static void *
isc__tls_realloc_ex(void *ptr, size_t size, const char *file, int line) {
UNUSED(file);
UNUSED(line);
return (isc_mem_reallocate(isc__tls_mctx, ptr, size));
}
static void
isc__tls_free_ex(void *ptr, const char *file, int line) {
UNUSED(file);
UNUSED(line);
if (ptr == NULL) {
return;
}
isc__mem_free(isc__tls_mctx, ptr);
}
#endif /* ISC_MEM_TRACKLINES */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static void
isc__tls_free(void *ptr) {
isc__tls_free_ex(ptr, __FILE__, __LINE__);
}
#endif
#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
void
isc__tls_initialize(void) {
isc_mem_create(&isc__tls_mctx);
isc_mem_setname(isc__tls_mctx, "OpenSSL");
isc_mem_setdestroycheck(isc__tls_mctx, false);
#if !defined(LIBRESSL_VERSION_NUMBER)
/*
* CRYPTO_set_mem_(_ex)_functions() returns 1 on success or 0 on
* failure, which means OpenSSL already allocated some memory. There's
* nothing we can do about it.
*/
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
(void)CRYPTO_set_mem_functions(isc__tls_malloc_ex, isc__tls_realloc_ex,
isc__tls_free_ex);
#else
(void)CRYPTO_set_mem_ex_functions(isc__tls_malloc_ex,
isc__tls_realloc_ex, isc__tls_free);
#endif
#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
RUNTIME_CHECK(OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN |
OPENSSL_INIT_LOAD_CONFIG,
NULL) == 1);
uint64_t opts = OPENSSL_INIT_ENGINE_ALL_BUILTIN |
OPENSSL_INIT_LOAD_CONFIG;
#if defined(OPENSSL_INIT_NO_ATEXIT)
/*
* We call OPENSSL_cleanup() manually, in a correct order, thus disable
* the automatic atexit() handler.
*/
opts |= OPENSSL_INIT_NO_ATEXIT;
#endif
RUNTIME_CHECK(OPENSSL_init_ssl(opts, NULL) == 1);
#else
nlocks = CRYPTO_num_locks();
/*
* We can't use isc_mem API here, because it's called too
* early and when the isc_mem_debugging flags are changed
* later.
*
* Actually, since this is a single allocation at library load
* and deallocation at library unload, using the standard
* allocator without the tracking is fine for this purpose.
*/
locks = calloc(nlocks, sizeof(locks[0]));
locks = isc_mem_get(isc__tls_mctx, nlocks * sizeof(locks[0]));
memset(locks, 0, nlocks * sizeof(locks[0]));
isc_mutexblock_init(locks, nlocks);
CRYPTO_set_locking_callback(isc__tls_lock_callback);
CRYPTO_THREADID_set_callback(isc__tls_set_thread_id);
@ -127,22 +214,10 @@ tls_initialize(void) {
"cannot be initialized (see the `PRNG not "
"seeded' message in the OpenSSL FAQ)");
}
atomic_compare_exchange_enforced(&init_done, &(bool){ false }, true);
}
void
isc__tls_initialize(void) {
isc_result_t result = isc_once_do(&init_once, tls_initialize);
REQUIRE(result == ISC_R_SUCCESS);
REQUIRE(atomic_load(&init_done));
}
static void
tls_shutdown(void) {
REQUIRE(atomic_load(&init_done));
REQUIRE(!atomic_load(&shut_done));
isc__tls_shutdown(void) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
OPENSSL_cleanup();
#else
@ -161,19 +236,17 @@ tls_shutdown(void) {
if (locks != NULL) {
isc_mutexblock_destroy(locks, nlocks);
free(locks);
isc_mem_put(isc__tls_mctx, locks, nlocks * sizeof(locks[0]));
locks = NULL;
}
#endif
atomic_compare_exchange_enforced(&shut_done, &(bool){ false }, true);
isc_mem_destroy(&isc__tls_mctx);
}
void
isc__tls_shutdown(void) {
isc_result_t result = isc_once_do(&shut_once, tls_shutdown);
REQUIRE(result == ISC_R_SUCCESS);
REQUIRE(atomic_load(&shut_done));
isc__tls_setdestroycheck(bool check) {
isc_mem_setdestroycheck(isc__tls_mctx, check);
}
void

View file

@ -13,6 +13,7 @@
#include <unistd.h>
#include <isc/mem.h>
#include <isc/util.h>
#include <isc/uv.h>
@ -97,3 +98,74 @@ isc__uverr2result(int uverr, bool dolog, const char *file, unsigned int line,
return (ISC_R_UNEXPECTED);
}
}
#if UV_VERSION_HEX >= UV_VERSION(1, 38, 0)
static isc_mem_t *isc__uv_mctx = NULL;
static void *
isc__uv_malloc(size_t size) {
return (isc_mem_allocate(isc__uv_mctx, size));
}
static void *
isc__uv_realloc(void *ptr, size_t size) {
return (isc_mem_reallocate(isc__uv_mctx, ptr, size));
}
static void *
isc__uv_calloc(size_t count, size_t size) {
void *ptr;
size_t res;
#if HAVE_BUILTIN_MUL_OVERFLOW
bool overflow = __builtin_mul_overflow(count, size, &res);
RUNTIME_CHECK(!overflow);
#else
res = count * size;
REQUIRE(count == 0 || res / count == size);
#endif
ptr = isc_mem_allocate(isc__uv_mctx, res);
memset(ptr, 0, res);
return (ptr);
}
static void
isc__uv_free(void *ptr) {
if (ptr == NULL) {
return;
}
isc_mem_free(isc__uv_mctx, ptr);
}
#endif /* UV_VERSION_HEX >= UV_VERSION(1, 38, 0) */
void
isc__uv_initialize(void) {
#if UV_VERSION_HEX >= UV_VERSION(1, 38, 0)
int r;
isc_mem_create(&isc__uv_mctx);
isc_mem_setname(isc__uv_mctx, "uv");
isc_mem_setdestroycheck(isc__uv_mctx, false);
r = uv_replace_allocator(isc__uv_malloc, isc__uv_realloc,
isc__uv_calloc, isc__uv_free);
UV_RUNTIME_CHECK(uv_replace_allocator, r);
#endif /* UV_VERSION_HEX >= UV_VERSION(1, 38, 0) */
}
void
isc__uv_shutdown(void) {
#if UV_VERSION_HEX >= UV_VERSION(1, 38, 0)
uv_library_shutdown();
isc_mem_destroy(&isc__uv_mctx);
#endif /* UV_VERSION_HEX < UV_VERSION(1, 38, 0) */
}
void
isc__uv_setdestroycheck(bool check) {
#if UV_VERSION_HEX >= UV_VERSION(1, 38, 0)
isc_mem_setdestroycheck(isc__uv_mctx, check);
#else
UNUSED(check);
#endif /* UV_VERSION_HEX >= UV_VERSION(1, 6, 0) */
}

79
lib/isc/xml.c Normal file
View file

@ -0,0 +1,79 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* 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/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#include <isc/mem.h>
#include <isc/util.h>
#include <isc/xml.h>
#ifdef HAVE_LIBXML2
#include <libxml/parser.h>
#include <libxml/xmlversion.h>
static isc_mem_t *isc__xml_mctx = NULL;
static void *
isc__xml_malloc(size_t size) {
return (isc_mem_allocate(isc__xml_mctx, size));
}
static void *
isc__xml_realloc(void *ptr, size_t size) {
return (isc_mem_reallocate(isc__xml_mctx, ptr, size));
}
static char *
isc__xml_strdup(const char *str) {
return (isc_mem_strdup(isc__xml_mctx, str));
}
static void
isc__xml_free(void *ptr) {
if (ptr == NULL) {
return;
}
isc_mem_free(isc__xml_mctx, ptr);
}
#endif /* HAVE_LIBXML2 */
void
isc__xml_initialize(void) {
#ifdef HAVE_LIBXML2
isc_mem_create(&isc__xml_mctx);
isc_mem_setname(isc__xml_mctx, "libxml2");
isc_mem_setdestroycheck(isc__xml_mctx, false);
RUNTIME_CHECK(xmlGcMemSetup(isc__xml_free, isc__xml_malloc,
isc__xml_malloc, isc__xml_realloc,
isc__xml_strdup) == 0);
xmlInitParser();
#endif /* HAVE_LIBXML2 */
}
void
isc__xml_shutdown(void) {
#ifdef HAVE_LIBXML2
xmlCleanupParser();
isc_mem_destroy(&isc__xml_mctx);
#endif /* HAVE_LIBXML2 */
}
void
isc__xml_setdestroycheck(bool check) {
#if HAVE_LIBXML2
isc_mem_setdestroycheck(isc__xml_mctx, check);
#else
UNUSED(check);
#endif
}

View file

@ -296,7 +296,7 @@ ISC_RUN_TEST_IMPL(isc_mem_reget) {
ISC_RUN_TEST_IMPL(isc_mem_noflags) {
isc_result_t result;
isc_mem_t *mctx2 = NULL;
char buf[4096], *p, *q;
char buf[4096], *p;
FILE *f;
void *ptr;
@ -305,13 +305,14 @@ ISC_RUN_TEST_IMPL(isc_mem_noflags) {
UNUSED(state);
isc_mem_create(&mctx2);
isc_mem_debugging = 0;
isc_mem_create(&mctx2);
ptr = isc_mem_get(mctx2, 2048);
assert_non_null(ptr);
isc__mem_printactive(mctx2, f);
isc_mem_put(mctx2, ptr, 2048);
isc_mem_destroy(&mctx2);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
isc_stdio_close(f);
memset(buf, 0, sizeof(buf));
@ -325,15 +326,7 @@ ISC_RUN_TEST_IMPL(isc_mem_noflags) {
buf[sizeof(buf) - 1] = 0;
p = strchr(buf, '\n');
assert_non_null(p);
assert_in_range(p, 0, buf + sizeof(buf) - 3);
p += 2;
q = strchr(p, '\n');
assert_non_null(q);
*q = '\0';
assert_string_equal(p, "None.");
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
assert_null(p);
}
/* test mem with record flag */
@ -390,13 +383,14 @@ ISC_RUN_TEST_IMPL(isc_mem_traceflag) {
UNUSED(state);
isc_mem_debugging = ISC_MEM_DEBUGRECORD | ISC_MEM_DEBUGTRACE;
isc_mem_create(&mctx2);
isc_mem_debugging = ISC_MEM_DEBUGTRACE;
ptr = isc_mem_get(mctx2, 2048);
assert_non_null(ptr);
isc__mem_printactive(mctx2, f);
isc_mem_put(mctx2, ptr, 2048);
isc_mem_destroy(&mctx2);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
isc_stdio_close(f);
memset(buf, 0, sizeof(buf));
@ -412,9 +406,13 @@ ISC_RUN_TEST_IMPL(isc_mem_traceflag) {
buf[sizeof(buf) - 1] = 0;
assert_memory_equal(buf, "add ", 4);
assert_memory_equal(buf, "create ", 6);
p = strchr(buf, '\n');
assert_non_null(p);
assert_memory_equal(p + 1, "add ", 4);
p = strchr(p + 1, '\n');
assert_non_null(p);
p = strchr(p + 1, '\n');
assert_non_null(p);
assert_in_range(p, 0, buf + sizeof(buf) - 3);
@ -422,8 +420,6 @@ ISC_RUN_TEST_IMPL(isc_mem_traceflag) {
p = strchr(p + 1, '\n');
assert_non_null(p);
assert_memory_equal(p + 1, "del ", 4);
isc_mem_debugging = ISC_MEM_DEBUGRECORD;
}
#endif /* if ISC_MEM_TRACKLINES */
@ -502,9 +498,6 @@ ISC_TEST_ENTRY(isc_mem_inuse)
ISC_TEST_ENTRY(isc_mem_zeroget)
ISC_TEST_ENTRY(isc_mem_reget)
#if !defined(__SANITIZE_THREAD__)
ISC_TEST_ENTRY(isc_mem_benchmark)
#endif /* __SANITIZE_THREAD__ */
#if ISC_MEM_TRACKLINES
ISC_TEST_ENTRY(isc_mem_noflags)
ISC_TEST_ENTRY(isc_mem_recordflag)
@ -515,6 +508,9 @@ ISC_TEST_ENTRY(isc_mem_recordflag)
*/
ISC_TEST_ENTRY(isc_mem_traceflag)
#endif /* if ISC_MEM_TRACKLINES */
#if !defined(__SANITIZE_THREAD__)
ISC_TEST_ENTRY(isc_mem_benchmark)
#endif /* __SANITIZE_THREAD__ */
ISC_TEST_LIST_END