Compare commits

...
Author SHA1 Message Date
Ondřej Surý 0c3d2cf703 Gotta make you understand 2021-02-04 20:36:44 +01:00
Ondřej Surý 52b16f0fe4 added some filthy stuff 2021-02-04 14:37:31 +01:00
Ondřej Surý 08903f1616 Make isc_mem_t and isc_mempool_t completely opaque
Previously isc_mem_t and isc_mempool_t had public header with magic
and matching full private types isc__mem_t and isc__mempool_t to
support non-BIND 9 API.  With turning the API to private to BIND 9, we
can make isc_mem_t and isc_mempool_t opaque data types and remove the
retyping from isc_mem_t to isc__mem_t in every call to isc_mem and
isc_mempool APIs.
2021-02-03 18:41:37 +01:00
Ondřej Surý dfde92a2f3 Disable isc_mem_checkdestroyed() in isc__mem_shutdown() 2021-02-03 18:41:37 +01:00
Ondřej SurýandOndřej Surý 642b2e0852 WIP: Needs split
Part 1: Move the constructor/destructor to lib/isc/lib.c as there's a
bug in Apple Clang that prevents the priority in
__attribute__((constructor|destructor)) to work properly across the
modules, e.g. all constructors and destructors needs to be listed in a
single compilation unit.

Part 2: Add proper support for compiling with different memory
allocators, initially, we have these memory allocators available:

1. the current custom BIND 9 allocator, which is default
2. the system library memory allocator
3. jemalloc memory allocator
4. tcmalloc memory allocator from gperftools

The work isn't 100% complete, as the non-default memory allocators are
missing the accounting, so the memory limits don't work at the moment.

The other suboptimal part is allocating chunks for the mempool, basically
the mempool should be fixed separately, as allocating the memory as
individual chunks is very suboptimal, it's slow and it leads to memory
fragmentation.
2021-02-03 18:41:37 +01:00
Ondřej SurýandOndřej Surý 82d567c7e8 Remove isc_mem_t.tag member and associated functions
The .tag member was used for "debugging", but it was actually always set
to NULL and never ever read, so this commit just removes it and remove
isc_mem_gettag() and modifies isc_mem_setname().
2021-02-03 18:38:35 +01:00
Ondřej SurýandOndřej Surý d8343bd004 Add isc_mem_callocate() and isc_mem_cget() functions
These two functions mimick the standard library calloc(num, size) function
by allocating num*size continuous memory and clearing the memory after
the allocation.
2021-02-03 18:38:35 +01:00
Ondřej SurýandOndřej Surý 7b8f198809 Remove an extra level of indirection in memory context routines
The memory context object formerly had an option to replace the memory
routines with own implementation when used outside of BIND 9.  The
ability to actually replace these was removed some time ago as the
libraries are now considered internal to BIND 9, and the default set of
the routines was always used.  The extra layer of indirection has been
removed now as well.
2021-02-03 18:38:34 +01:00
Ondřej SurýandOndřej Surý beb0243bd4 Use BIND 9 memory allocator with libuv
The libuv library can use external memory allocators by calling
uv_replace_allocators() before using the library.  And
isc__nm_initialize() constructor and isc__nm_shutdown() destructor
that setups the libuv to use the default memory context and
isc_malloc(), ... isc_free() routines.

As our memory allocator requires all memory to be freed before the
memory context is destroyed, we also the uv_library_shutdown() call
which is available only since libuv >= 1.38.0.
2021-02-03 18:36:39 +01:00
Ondřej SurýandOndřej Surý dcaa3a785e Add default memory context and stdlib-like memory management
The BIND 9 memory model always requires a memory context to be used with
any functions that want to allocate memory.  The BIND 9 memory allocator
has several advantages on top of default memory allocator (small-chunk
memory allocator, memory limits, statistics, memory tracking, ...), but
it also complicates some use scenarios:

* Integration our memory allocator with third party libraries that
  usually requires standard memory functions (f.e. libuv requires malloc,
  calloc, realloc and free to be available)

* Every single application using libisc has to create a memory context
  first and then pass it to underlying functions

* Not even ever internal use case cares about the extra features and
  would benefit from not having to track the memory allocator.

* Integration with external allocator libraries (tcmalloc, jemalloc)
  is complicated and it mostly loses the benefits of said external
  allocator by adding yet another layer(s) on top of it.

This commit uses the constructor/destructor attribute[1] with gcc/clang
and DllMain[2] with MSVC to create a default memory context that's
always available and adds isc_malloc(), isc_calloc(), isc_realloc(),
isc_free() and isc_strdup() set of functions that operates on top of the
default memory context.

1. https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
2. https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain
2021-02-03 18:36:13 +01:00
Ondřej SurýandOndřej Surý c7392f92ea Disable calling DllMain() on thread creation/destruction
Disables the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications for
the specified dynamic-link library (DLL).  This can reduce the size of
the working set for some applications.
2021-02-03 18:36:13 +01:00
26 changed files with 1081 additions and 881 deletions
+1 -1
View File
@@ -1401,7 +1401,7 @@ setup_libs(void) {
}
isc_mem_create(&mctx);
isc_mem_setname(mctx, "dig", NULL);
isc_mem_setname(mctx, "dig");
isc_log_create(mctx, &lctx, &logconfig);
isc_log_setcontext(lctx);
+1 -2
View File
@@ -1555,7 +1555,7 @@ main(int argc, char *argv[]) {
}
isc_mem_create(&named_g_mctx);
isc_mem_setname(named_g_mctx, "main", NULL);
isc_mem_setname(named_g_mctx, "main");
setup();
@@ -1614,7 +1614,6 @@ main(int argc, char *argv[]) {
}
}
isc_mem_destroy(&named_g_mctx);
isc_mem_checkdestroyed(stderr);
named_main_setmemstats(NULL);
+2 -2
View File
@@ -4613,9 +4613,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
* memory.
*/
isc_mem_create(&cmctx);
isc_mem_setname(cmctx, "cache", NULL);
isc_mem_setname(cmctx, "cache");
isc_mem_create(&hmctx);
isc_mem_setname(hmctx, "cache_heap", NULL);
isc_mem_setname(hmctx, "cache_heap");
CHECK(dns_cache_create(cmctx, hmctx, named_g_taskmgr,
named_g_timermgr, view->rdclass,
cachename, "rbt", 0, NULL,
+25
View File
@@ -1580,6 +1580,31 @@ test -z "$with_dlz_stub" && with_dlz_stub=no
AC_CHECK_HEADERS([glob.h])
#
# Support for constructor and destructor attributes
#
AX_GCC_FUNC_ATTRIBUTE([constructor])
AX_GCC_FUNC_ATTRIBUTE([destructor])
#
# Which memory allocator we should use?
#
AC_ARG_WITH([allocator],
[AS_HELP_STRING([--with-allocator=<custom|system|jemalloc|tcmalloc|tcmalloc_minimal>],
[Use different memory allocator (default=custom)])],
[],
[with_allocator=custom])
AS_CASE([$with_allocator],
[system], [AC_DEFINE([USE_ALLOCATOR_SYSTEM], [1], [Define if you want to use system memory allocator])],
[jemalloc], [PKG_CHECK_MODULES([ALLOCATOR], [jemalloc],
[AC_DEFINE([USE_ALLOCATOR_JEMALLOC], [1], [Define if you want to use jemalloc allocator])])],
[tcmalloc*], [PKG_CHECK_MODULES([ALLOCATOR], [lib$with_allocator],
[AC_DEFINE([USE_ALLOCATOR_TCMALLOC], [1], [Define if you want to use tcmalloc allocator])])],
[AC_DEFINE([USE_ALLOCATOR_CUSTOM], [1], [Define if you want to use custom BIND 9 allocator])])
AC_MSG_NOTICE([Using $with_allocator memory allocator])
#
# Files to configure. These are listed here because we used to
# specify them as arguments to AC_OUTPUT.
+1 -1
View File
@@ -201,7 +201,7 @@ dst_lib_init(isc_mem_t *mctx, const char *engine) {
RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
RETERR(dst__openssl_init(mctx, engine));
RETERR(dst__openssl_init(engine));
RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
#if USE_OPENSSL
RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1],
+1 -1
View File
@@ -201,7 +201,7 @@ struct dst_func {
* Initializers
*/
isc_result_t
dst__openssl_init(isc_mem_t *, const char *engine);
dst__openssl_init(const char *engine);
#define dst__pkcs11_init pk11_initialize
isc_result_t
+3 -77
View File
@@ -39,8 +39,6 @@
#include "dst_internal.h"
#include "dst_openssl.h"
static isc_mem_t *dst__mctx = NULL;
#if !defined(OPENSSL_NO_ENGINE)
#include <openssl/engine.h>
#endif /* if !defined(OPENSSL_NO_ENGINE) */
@@ -49,54 +47,13 @@ static isc_mem_t *dst__mctx = NULL;
static ENGINE *e = NULL;
#endif /* if !defined(OPENSSL_NO_ENGINE) */
static void
enable_fips_mode(void) {
#ifdef HAVE_FIPS_MODE
if (FIPS_mode() != 0) {
/*
* FIPS mode is already enabled.
*/
return;
}
if (FIPS_mode_set(1) == 0) {
dst__openssl_toresult2("FIPS_mode_set", DST_R_OPENSSLFAILURE);
exit(1);
}
#endif /* HAVE_FIPS_MODE */
}
isc_result_t
dst__openssl_init(isc_mem_t *mctx, const char *engine) {
dst__openssl_init(const char *engine) {
isc_result_t result;
REQUIRE(dst__mctx == NULL);
isc_mem_attach(mctx, &dst__mctx);
#if defined(OPENSSL_NO_ENGINE)
UNUSED(engine);
#endif /* if defined(OPENSSL_NO_ENGINE) */
enable_fips_mode();
isc_tls_initialize();
#if !defined(OPENSSL_NO_ENGINE)
#if !defined(CONF_MFLAGS_DEFAULT_SECTION)
OPENSSL_config(NULL);
#else /* if !defined(CONF_MFLAGS_DEFAULT_SECTION) */
/*
* OPENSSL_config() can only be called a single time as of
* 1.0.2e so do the steps individually.
*/
OPENSSL_load_builtin_modules();
ENGINE_load_builtin_engines();
ERR_clear_error();
CONF_modules_load_file(NULL, NULL,
CONF_MFLAGS_DEFAULT_SECTION |
CONF_MFLAGS_IGNORE_MISSING_FILE);
#endif /* if !defined(CONF_MFLAGS_DEFAULT_SECTION) */
#else /* if defined(OPENSSL_NO_ENGINE) */
if (engine != NULL && *engine == '\0') {
engine = NULL;
}
@@ -116,14 +73,6 @@ dst__openssl_init(isc_mem_t *mctx, const char *engine) {
#endif /* !defined(OPENSSL_NO_ENGINE) */
/* Protect ourselves against unseeded PRNG */
if (RAND_status() != 1) {
FATAL_ERROR(__FILE__, __LINE__,
"OpenSSL pseudorandom number generator "
"cannot be initialized (see the `PRNG not "
"seeded' message in the OpenSSL FAQ)");
}
return (ISC_R_SUCCESS);
#if !defined(OPENSSL_NO_ENGINE)
@@ -138,30 +87,7 @@ cleanup_rm:
void
dst__openssl_destroy(void) {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
/*
* Sequence taken from apps_shutdown() in <apps/apps.h>.
*/
CONF_modules_free();
OBJ_cleanup();
EVP_cleanup();
#if !defined(OPENSSL_NO_ENGINE)
if (e != NULL) {
ENGINE_free(e);
}
e = NULL;
ENGINE_cleanup();
#endif /* if !defined(OPENSSL_NO_ENGINE) */
CRYPTO_cleanup_all_ex_data();
ERR_clear_error();
#ifdef DNS_CRYPTO_LEAKS
CRYPTO_mem_leaks_fp(stderr);
#endif /* ifdef DNS_CRYPTO_LEAKS */
#endif
isc_tls_destroy();
isc_mem_detach(&dst__mctx);
/* Empty */
}
static isc_result_t
+1 -1
View File
@@ -10410,7 +10410,7 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr,
* enabling threads because it will be require more memory.
*/
isc_mem_create(&res->buckets[i].mctx);
isc_mem_setname(res->buckets[i].mctx, name, NULL);
isc_mem_setname(res->buckets[i].mctx, name);
isc_task_setname(res->buckets[i].task, name, res);
ISC_LIST_INIT(res->buckets[i].fctxs);
atomic_init(&res->buckets[i].exiting, false);
+1 -1
View File
@@ -828,7 +828,7 @@ dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr,
isc_mem_create(&mctx);
result = dns_adb_create(mctx, view, timermgr, taskmgr, &view->adb);
isc_mem_setname(mctx, "ADB", NULL);
isc_mem_setname(mctx, "ADB");
isc_mem_detach(&mctx);
if (result != ISC_R_SUCCESS) {
dns_resolver_shutdown(view->resolver);
+1 -1
View File
@@ -18352,7 +18352,7 @@ mctxinit(void **target, void *arg) {
REQUIRE(target != NULL && *target == NULL);
isc_mem_create(&mctx);
isc_mem_setname(mctx, "zonemgr-pool", NULL);
isc_mem_setname(mctx, "zonemgr-pool");
*target = mctx;
return (ISC_R_SUCCESS);
+2
View File
@@ -226,6 +226,7 @@ libisc_la_SOURCES = \
libisc_la_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(ALLOCATOR_CFLAGS) \
$(LIBISC_CFLAGS) \
$(LIBUV_CFLAGS) \
$(OPENSSL_CFLAGS) \
@@ -236,6 +237,7 @@ libisc_la_LDFLAGS = \
-release "$(PACKAGE_VERSION)"
libisc_la_LIBADD = \
$(ALLOCATOR_LIBS) \
$(LIBUV_LIBS) \
$(OPENSSL_LIBS) \
$(ZLIB_LIBS)
+3 -13
View File
@@ -553,8 +553,7 @@ isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer,
isc_result_t
isc_buffer_reserve(isc_buffer_t **dynbuffer, unsigned int size) {
unsigned char *bdata;
uint64_t len;
size_t len;
REQUIRE(dynbuffer != NULL);
REQUIRE(ISC_BUFFER_VALID(*dynbuffer));
@@ -581,18 +580,9 @@ isc_buffer_reserve(isc_buffer_t **dynbuffer, unsigned int size) {
return (ISC_R_NOMEMORY);
}
/*
* XXXMUKS: This is far more expensive than plain realloc() as
* it doesn't remap pages, but does ordinary copy. So is
* isc_mem_reallocate(), which has additional issues.
*/
bdata = isc_mem_get((*dynbuffer)->mctx, (unsigned int)len);
(*dynbuffer)->base = isc_mem_reallocate((*dynbuffer)->mctx,
(*dynbuffer)->base, len);
memmove(bdata, (*dynbuffer)->base, (*dynbuffer)->length);
isc_mem_put((*dynbuffer)->mctx, (*dynbuffer)->base,
(*dynbuffer)->length);
(*dynbuffer)->base = bdata;
(*dynbuffer)->length = (unsigned int)len;
return (ISC_R_SUCCESS);
+48 -84
View File
@@ -32,24 +32,13 @@ typedef void (*isc_mem_water_t)(void *, int);
* Define ISC_MEM_TRACKLINES=1 to turn on detailed tracing of memory
* allocation and freeing by file and line number.
*/
#if !defined(USE_ALLOCATOR_SYSTEM) && !defined(USE_ALLOCATOR_JEMALLOC) && \
!defined(USE_ALLOCATOR_TCMALLOC)
#ifndef ISC_MEM_TRACKLINES
#define ISC_MEM_TRACKLINES 1
#endif /* ifndef ISC_MEM_TRACKLINES */
/*%
* Define ISC_MEM_CHECKOVERRUN=1 to turn on checks for using memory outside
* the requested space. This will increase the size of each allocation.
*
* If we are performing a Coverity static analysis then ISC_MEM_CHECKOVERRUN
* can hide bugs that would otherwise discovered so force to zero.
*/
#ifdef __COVERITY__
#undef ISC_MEM_CHECKOVERRUN
#define ISC_MEM_CHECKOVERRUN 0
#endif /* ifdef __COVERITY__ */
#ifndef ISC_MEM_CHECKOVERRUN
#define ISC_MEM_CHECKOVERRUN 1
#endif /* ifndef ISC_MEM_CHECKOVERRUN */
#endif /* !defined(USE_ALLOCATOR_SYSTEM) && !defined(USE_ALLOCATOR_JEMALLOC) \
&& !defined(USE_ALLOCATOR_TCMALLOC) */
/*%
* Define ISC_MEMPOOL_NAMES=1 to make memory pools store a symbolic
@@ -98,26 +87,8 @@ LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_defaultflags;
*/
/*@}*/
#if ISC_MEM_TRACKLINES
#define _ISC_MEM_FILELINE , __FILE__, __LINE__
#define _ISC_MEM_FLARG , const char *, unsigned int
#else /* if ISC_MEM_TRACKLINES */
#define _ISC_MEM_FILELINE
#define _ISC_MEM_FLARG
#endif /* if ISC_MEM_TRACKLINES */
/*!
* Define ISC_MEM_USE_INTERNAL_MALLOC=1 to use the internal malloc()
* implementation in preference to the system one. The internal malloc()
* is very space-efficient, and quite fast on uniprocessor systems. It
* performs poorly on multiprocessor machines.
* JT: we can overcome the performance issue on multiprocessor machines
* by carefully separating memory contexts.
*/
#ifndef ISC_MEM_USE_INTERNAL_MALLOC
#define ISC_MEM_USE_INTERNAL_MALLOC 1
#endif /* ifndef ISC_MEM_USE_INTERNAL_MALLOC */
/*
* Flags for isc_mem_create() calls.
@@ -162,21 +133,6 @@ LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_defaultflags;
* \endcode
*/
/*% memory and memory pool methods */
typedef struct isc_memmethods {
void *(*memget)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG);
void (*memput)(isc_mem_t *mctx, void *ptr, size_t size _ISC_MEM_FLARG);
void (*memputanddetach)(isc_mem_t **mctxp, void *ptr,
size_t size _ISC_MEM_FLARG);
void *(*memallocate)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG);
void *(*memreallocate)(isc_mem_t *mctx, void *ptr,
size_t size _ISC_MEM_FLARG);
char *(*memstrdup)(isc_mem_t *mctx, const char *s _ISC_MEM_FLARG);
char *(*memstrndup)(isc_mem_t *mctx, const char *s,
size_t size _ISC_MEM_FLARG);
void (*memfree)(isc_mem_t *mctx, void *ptr _ISC_MEM_FLARG);
} isc_memmethods_t;
/*%
* This structure is actually just the common prefix of a memory context
* implementation's version of an isc_mem_t.
@@ -186,27 +142,13 @@ typedef struct isc_memmethods {
* isc_mem_ routines to work. mctx implementations must maintain all mctx
* invariants.
*/
struct isc_mem {
unsigned int impmagic;
unsigned int magic;
isc_memmethods_t *methods;
};
#define ISCAPI_MCTX_MAGIC ISC_MAGIC('A', 'm', 'c', 'x')
#define ISCAPI_MCTX_VALID(m) ((m) != NULL && (m)->magic == ISCAPI_MCTX_MAGIC)
struct isc_mem;
/*%
* This is the common prefix of a memory pool context. The same note as
* that for the mem structure applies.
*/
struct isc_mempool {
unsigned int impmagic;
unsigned int magic;
};
#define ISCAPI_MPOOL_MAGIC ISC_MAGIC('A', 'm', 'p', 'l')
#define ISCAPI_MPOOL_VALID(mp) \
((mp) != NULL && (mp)->magic == ISCAPI_MPOOL_MAGIC)
struct isc_mempool;
/*%
* These functions are actually implemented in isc__mem_<function>
@@ -223,8 +165,11 @@ struct isc_mempool {
#define ISCMEMFUNC(sfx) isc__mem_##sfx
#define ISCMEMPOOLFUNC(sfx) isc__mempool_##sfx
#define isc_mem_get(c, s) ISCMEMFUNC(get)((c), (s)_ISC_MEM_FILELINE)
#define isc_mem_get(c, s) ISCMEMFUNC(get)((c), (s)_ISC_MEM_FILELINE)
#define isc_mem_cget(c, n, s) ISCMEMFUNC(cget((c), (n), (s)_ISC_MEM_FILELINE)
#define isc_mem_allocate(c, s) ISCMEMFUNC(allocate)((c), (s)_ISC_MEM_FILELINE)
#define isc_mem_callocate(c, n, s) \
ISCMEMFUNC(callocate)((c), (n), (s)_ISC_MEM_FILELINE)
#define isc_mem_reallocate(c, p, s) \
ISCMEMFUNC(reallocate)((c), (p), (s)_ISC_MEM_FILELINE)
#define isc_mem_strdup(c, p) ISCMEMFUNC(strdup)((c), (p)_ISC_MEM_FILELINE)
@@ -390,7 +335,7 @@ isc_mem_references(isc_mem_t *ctx);
*/
void
isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag);
isc_mem_setname(isc_mem_t *ctx, const char *name);
/*%<
* Name 'ctx'.
*
@@ -398,8 +343,6 @@ isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag);
*
*\li Only the first 15 characters of 'name' will be copied.
*
*\li 'tag' is for debugging purposes only.
*
* Requires:
*
*\li 'ctx' is a valid ctx.
@@ -419,21 +362,6 @@ isc_mem_getname(isc_mem_t *ctx);
* empty.
*/
void *
isc_mem_gettag(isc_mem_t *ctx);
/*%<
* Get the tag value for 'task', as previously set using isc_mem_setname().
*
* Requires:
*\li 'ctx' is a valid ctx.
*
* Notes:
*\li This function is for debugging purposes only.
*
* Requires:
*\li 'ctx' is a valid task.
*/
#ifdef HAVE_LIBXML2
int
isc_mem_renderxml(void *writer0);
@@ -454,8 +382,10 @@ isc_mem_renderjson(void *memobj0);
* Memory pools
*/
#define isc_mempool_create(mctx, size, mpctxp) \
isc__mempool_create(mctx, size, mpctxp _ISC_MEM_FILELINE)
void
isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp);
isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp _ISC_MEM_FLARG);
/*%<
* Create a memory pool.
*
@@ -594,9 +524,11 @@ isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit);
* Pseudo-private functions for use via macros. Do not call directly.
*/
void *ISCMEMFUNC(get)(isc_mem_t *, size_t _ISC_MEM_FLARG);
void *ISCMEMFUNC(cget)(isc_mem_t *, size_t, size_t _ISC_MEM_FLARG);
void ISCMEMFUNC(putanddetach)(isc_mem_t **, void *, size_t _ISC_MEM_FLARG);
void ISCMEMFUNC(put)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
void *ISCMEMFUNC(allocate)(isc_mem_t *, size_t _ISC_MEM_FLARG);
void *ISCMEMFUNC(callocate)(isc_mem_t *, size_t, size_t _ISC_MEM_FLARG);
void *ISCMEMFUNC(reallocate)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
void ISCMEMFUNC(free)(isc_mem_t *, void *_ISC_MEM_FLARG);
char *ISCMEMFUNC(strdup)(isc_mem_t *, const char *_ISC_MEM_FLARG);
@@ -604,6 +536,38 @@ char *ISCMEMFUNC(strndup)(isc_mem_t *, const char *, size_t _ISC_MEM_FLARG);
void *ISCMEMPOOLFUNC(get)(isc_mempool_t *_ISC_MEM_FLARG);
void ISCMEMPOOLFUNC(put)(isc_mempool_t *, void *_ISC_MEM_FLARG);
/*
* Memory management routines using default memory context
*/
#define isc_malloc(size) isc__malloc((size)_ISC_MEM_FILELINE)
#define isc_calloc(num, size) isc__calloc((num), (size)_ISC_MEM_FILELINE)
#define isc_realloc(ptr, size) isc__realloc((ptr), (size)_ISC_MEM_FILELINE)
#define isc_free(ptr) isc__free((ptr)_ISC_MEM_FILELINE)
#define isc_strdup(str) isc__strdup((str)_ISC_MEM_FILELINE)
#define isc_strndup(str) isc__strndup((str)_ISC_MEM_FILELINE)
void *
isc__malloc(size_t size _ISC_MEM_FLARG);
void *
isc__calloc(size_t num, size_t size _ISC_MEM_FLARG);
void *
isc__realloc(void *ptr, size_t size _ISC_MEM_FLARG);
void
isc__free(void *ptr _ISC_MEM_FLARG);
char *
isc__strdup(const char *str _ISC_MEM_FLARG);
char *
isc__strndup(const char *str, size_t size _ISC_MEM_FLARG);
isc_mem_t *
isc_get_default_mctx(void);
void
isc_mem_initialize(void);
void
isc_mem_shutdown(void);
ISC_LANG_ENDDECLS
#endif /* ISC_MEM_H */
+6
View File
@@ -548,3 +548,9 @@ isc_result_t
isc_nm_http_add_doh_endpoint(isc_nmsocket_t *sock, const char *uri,
isc_nm_recv_cb_t cb, void *cbarg,
size_t extrahandlesize);
void
isc_nm_initialize(void);
void
isc_nm_shutdown(void);
+1 -1
View File
@@ -23,7 +23,7 @@ void
isc_tls_initialize(void);
void
isc_tls_destroy(void);
isc_tls_shutdown(void);
void
isc_tlsctx_free(isc_tlsctx_t **ctpx);
+23
View File
@@ -48,6 +48,16 @@
#define ISC_NONSTRING
#endif /* __GNUC__ */
#if HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR && HAVE_FUNC_ATTRIBUTE_DESTRUCTOR
#define ISC_CONSTRUCTOR(priority) __attribute__((constructor(priority)))
#define ISC_DESTRUCTOR(priority) __attribute__((destructor(priority)))
#elif WIN32
#define ISC_CONSTRUCTOR(priority)
#define ISC_DESTRUCTOR(priority)
#else
#error Either __attribute__((constructor|destructor))__ or DllMain support needed to compile BIND 9.
#endif
/*%
* The opposite: silent warnings about stored values which are never read.
*/
@@ -200,6 +210,10 @@
#define __has_feature(x) 0
#endif /* if !defined(__has_feature) */
#if !defined(__has_builtin)
#define __has_builtin(x) 0
#endif /* if !defined(__has_attribute) */
/* GCC defines __SANITIZE_ADDRESS__, so reuse the macro for clang */
#if __has_feature(address_sanitizer)
#define __SANITIZE_ADDRESS__ 1
@@ -340,6 +354,15 @@ mock_assert(const int result, const char *const expression,
#define ISC_ALIGN(x, a) (((x) + (a)-1) & ~((uintmax_t)(a)-1))
#endif /* ifdef __GNUC__ */
/*%
* Overflow checks
*/
#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5
#define ISC_MUL_OVERFLOW(a, b, res) __builtin_mul_overflow(a, b, res)
#else
#define ISC_MUL_OVERFLOW(a, b, res) ((*res) = (a) * (b))
#endif
/*%
* Misc
*/
+25
View File
@@ -11,8 +11,14 @@
/*! \file */
#include <uv.h>
#include <isc/bind9.h>
#include <isc/lib.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/tls.h>
#include <isc/util.h>
/***
*** Functions
@@ -22,3 +28,22 @@ void
isc_lib_register(void) {
isc_bind9 = false;
}
void
isc__initialize(void) ISC_CONSTRUCTOR(101);
void
isc__shutdown(void) ISC_DESTRUCTOR(101);
void
isc__initialize(void) {
isc_mem_initialize(); /* Priority 102 */
isc_tls_initialize(); /* Priority 103 */
isc_nm_initialize(); /* Priority 104 */
}
void
isc__shutdown(void) {
isc_nm_shutdown(); /* Priority 104 */
isc_tls_shutdown(); /* Priority 103 */
isc_mem_shutdown(); /* Priority 102 */
}
+727 -656
View File
File diff suppressed because it is too large Load Diff
+42 -4
View File
@@ -216,8 +216,6 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) {
isc__nm_winsock_initialize();
#endif /* WIN32 */
isc_tls_initialize();
mgr = isc_mem_get(mctx, sizeof(*mgr));
*mgr = (isc_nm_t){ .nworkers = workers };
@@ -374,8 +372,6 @@ nm_destroy(isc_nm_t **mgr0) {
mgr->nworkers * sizeof(isc__networker_t));
isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
isc_tls_destroy();
#ifdef WIN32
isc__nm_winsock_destroy();
#endif /* WIN32 */
@@ -2521,3 +2517,45 @@ isc__nm_dump_active(isc_nm_t *nm) {
UNLOCK(&nm->lock);
}
#endif
#if UV_VERSION_MAJOR > 1 || (UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR >= 38)
static void *
isc__nm_malloc(size_t size) {
return (isc_malloc(size));
}
static void *
isc__nm_calloc(size_t num, size_t size) {
return (isc_calloc(num, size));
}
static void *
isc__nm_realloc(void *ptr, size_t size) {
return (isc_realloc(ptr, size));
}
static void
isc__nm_free(void *ptr) {
return (isc_free(ptr));
}
void
isc_nm_initialize(void) {
uv_replace_allocator(isc__nm_malloc, isc__nm_realloc, isc__nm_calloc, isc__nm_free);
}
void
isc_nm_shutdown(void) {
uv_library_shutdown();
}
#else
void
isc_nm_initialize(void) {}
void
isc_nm_shutdown(void) {}
#endif
+4
View File
@@ -38,6 +38,8 @@ _setup(void **state) {
UNUSED(state);
fprintf(stderr, "%s\n", __func__);
result = isc_test_begin(NULL, true, 0);
assert_int_equal(result, ISC_R_SUCCESS);
@@ -48,6 +50,8 @@ static int
_teardown(void **state) {
UNUSED(state);
fprintf(stderr, "%s\n", __func__);
isc_test_end();
return (0);
+3 -5
View File
@@ -67,7 +67,7 @@ cleanup_managers(void) {
isc_timermgr_destroy(&timermgr);
}
if (netmgr != NULL) {
isc_nm_detach(&netmgr);
isc_nm_destroy(&netmgr);
}
}
@@ -108,7 +108,6 @@ isc_test_begin(FILE *logfile, bool start_managers, unsigned int workers) {
isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
INSIST(test_mctx == NULL);
isc_mem_create(&test_mctx);
if (logfile != NULL) {
@@ -156,9 +155,8 @@ isc_test_end(void) {
if (test_lctx != NULL) {
isc_log_destroy(&test_lctx);
}
if (test_mctx != NULL) {
isc_mem_destroy(&test_mctx);
}
isc_mem_detach(&test_mctx);
test_running = false;
}
+42 -10
View File
@@ -64,6 +64,22 @@ _teardown(void **state) {
#define MP2_FREEMAX 25
#define MP2_FILLCNT 25
#define ALIGNMENT_SIZE sizeof(void *)
static inline size_t
quantize(size_t size) {
/*!
* Round up the result in order to get a size big
* enough to satisfy the request and be aligned on ALIGNMENT_SIZE
* byte boundaries.
*/
if (size == 0U) {
return (ALIGNMENT_SIZE);
}
return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1)));
}
/* general memory system tests */
static void
isc_mem_test(void **state) {
@@ -72,7 +88,7 @@ isc_mem_test(void **state) {
void *tmp;
isc_mempool_t *mp1 = NULL, *mp2 = NULL;
unsigned int i, j;
int rval;
int rval, mp1_freecount = 0;
UNUSED(state);
@@ -91,6 +107,12 @@ isc_mem_test(void **state) {
assert_non_null(items1[i]);
}
/*
* The number of free items on the list will be MAX(MP1_FREEMAX,
* MP1_MAXALLOC) aligned to page boundary.
*/
mp1_freecount = isc_mempool_getfreecount(mp1);
/*
* Try to allocate one more. This should fail.
*/
@@ -107,7 +129,7 @@ isc_mem_test(void **state) {
}
rval = isc_mempool_getfreecount(mp1);
assert_int_equal(rval, 10);
assert_int_equal(rval, mp1_freecount + 11);
rval = isc_mempool_getallocated(mp1);
assert_int_equal(rval, 19);
@@ -152,6 +174,9 @@ isc_mem_test(void **state) {
isc_mempool_destroy(&mp1);
}
#if !defined(USE_ALLOCATOR_SYSTEM) && !defined(USE_ALLOCATOR_JEMALLOC) && \
!defined(USE_ALLOCATOR_TCMALLOC)
/* test TotalUse calculation */
static void
isc_mem_total_test(void **state) {
@@ -205,8 +230,7 @@ isc_mem_total_test(void **state) {
static void
isc_mem_inuse_test(void **state) {
isc_mem_t *mctx2 = NULL;
size_t before, after;
ssize_t diff;
size_t before, meanwhile, after;
void *ptr;
UNUSED(state);
@@ -216,16 +240,22 @@ isc_mem_inuse_test(void **state) {
before = isc_mem_inuse(mctx2);
ptr = isc_mem_allocate(mctx2, 1024000);
meanwhile = isc_mem_inuse(mctx2);
isc_mem_free(mctx2, ptr);
after = isc_mem_inuse(mctx2);
diff = after - before;
assert_int_equal(diff, 0);
isc_mem_destroy(&mctx2);
fprintf(stderr, "%zu < %zu > %zu\n", before, meanwhile, after);
assert_int_not_equal(before, meanwhile);
assert_true(before < meanwhile);
assert_int_not_equal(meanwhile, after);
assert_true(after < meanwhile);
assert_int_equal(after, before);
}
#endif
#if ISC_MEM_TRACKLINES
/* test mem with no flags */
@@ -497,11 +527,13 @@ main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(isc_mem_test, _setup,
_teardown),
#if !defined(USE_ALLOCATOR_SYSTEM) && !defined(USE_ALLOCATOR_JEMALLOC) && \
!defined(USE_ALLOCATOR_TCMALLOC)
cmocka_unit_test_setup_teardown(isc_mem_total_test, _setup,
_teardown),
cmocka_unit_test_setup_teardown(isc_mem_inuse_test, _setup,
_teardown),
#endif
#if !defined(__SANITIZE_THREAD__)
cmocka_unit_test_setup_teardown(isc_mem_benchmark, _setup,
_teardown),
+90 -7
View File
@@ -9,6 +9,7 @@
* information regarding copyright ownership.
*/
#include <openssl/conf.h>
#include <openssl/err.h>
#include <openssl/opensslv.h>
@@ -46,14 +47,71 @@ static void
isc__tls_set_thread_id(CRYPTO_THREADID *id) {
CRYPTO_THREADID_set_numeric(id, (unsigned long)isc_thread_self());
}
# if !defined(OPENSSL_NO_ENGINE)
# define apps_startup() { \
CRYPTO_malloc_init(); \
ERR_load_crypto_strings(); \
OpenSSL_add_all_algorithms(); \
ENGINE_load_builtin_engines(); \
}
# define apps_shutdown() { \
CONF_modules_unload(1); \
OBJ_cleanup(); \
EVP_cleanup(); \
ENGINE_cleanup(); \
CRYPTO_cleanup_all_ex_data(); \
ERR_remove_thread_state(NULL); \
RAND_cleanup(); \
ERR_free_strings(); \
}
# else
# define apps_startup() { \
CRYPTO_malloc_init(); \
ERR_load_crypto_strings(); \
OpenSSL_add_all_algorithms(); \
}
# define apps_shutdown() { \
CONF_modules_unload(1); \
OBJ_cleanup(); \
EVP_cleanup(); \
CRYPTO_cleanup_all_ex_data(); \
ERR_remove_thread_state(NULL); \
RAND_cleanup(); \
ERR_free_strings(); \
}
# endif
#endif
static void
enable_fips_mode(void) {
#ifdef HAVE_FIPS_MODE
if (FIPS_mode() != 0) {
/*
* FIPS mode is already enabled.
*/
return;
}
if (FIPS_mode_set(1) == 0) {
FATAL_ERROR(__FILE__, __LINE__,
"OpenSSL FIPS mode cannot be set");
exit(1);
}
#endif /* HAVE_FIPS_MODE */
}
static void
isc__tls_initialize(void) {
REQUIRE(!atomic_load(&init_done));
RUNTIME_CHECK(OPENSSL_init_ssl(0, NULL) == 1);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
enable_fips_mode();
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
RUNTIME_CHECK(OPENSSL_init_ssl(OPENSSL_INIT_ENGINE_ALL_BUILTIN
| OPENSSL_INIT_LOAD_CONFIG, NULL) == 1);
#else
isc_mem_create(&isc__tls_mctx);
nlocks = CRYPTO_num_locks();
@@ -61,8 +119,25 @@ isc__tls_initialize(void) {
isc_mutexblock_init(locks, nlocks);
CRYPTO_set_locking_callback(isc__tls_lock_callback);
CRYPTO_THREADID_set_callback(isc__tls_set_thread_id);
ERR_load_crypto_strings();
apps_startup();
#endif
#if !defined(CONF_MFLAGS_DEFAULT_SECTION)
OPENSSL_config(NULL);
#else /* if !defined(CONF_MFLAGS_DEFAULT_SECTION) */
/*
* OPENSSL_config() can only be called a single time as of
* 1.0.2e so do the steps individually.
*/
OPENSSL_load_builtin_modules();
ENGINE_load_builtin_engines();
ERR_clear_error();
CONF_modules_load_file(NULL, NULL,
CONF_MFLAGS_DEFAULT_SECTION |
CONF_MFLAGS_IGNORE_MISSING_FILE);
#endif /* if !defined(CONF_MFLAGS_DEFAULT_SECTION) */
atomic_store(&init_done, true);
}
@@ -71,15 +146,23 @@ isc_tls_initialize(void) {
isc_result_t result = isc_once_do(&init_once, isc__tls_initialize);
REQUIRE(result == ISC_R_SUCCESS);
REQUIRE(atomic_load(&init_done));
/* Protect ourselves against unseeded PRNG */
if (RAND_status() != 1) {
FATAL_ERROR(__FILE__, __LINE__,
"OpenSSL pseudorandom number generator "
"cannot be initialized (see the `PRNG not "
"seeded' message in the OpenSSL FAQ)");
}
}
void
isc_tls_destroy(void) {
isc_tls_shutdown(void) {
REQUIRE(atomic_load(&init_done));
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
ERR_free_strings();
ERR_remove_thread_state(NULL);
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
apps_shutdown();
CRYPTO_set_locking_callback(NULL);
if (locks != NULL) {
+27 -12
View File
@@ -12,6 +12,10 @@
#include <stdio.h>
#include <windows.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/tls.h>
/*
* Called when we enter the DLL
*/
@@ -19,25 +23,36 @@ __declspec(dllexport) BOOL WINAPI
DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
switch (fdwReason) {
/*
* The DLL is loading due to process
* initialization or a call to LoadLibrary.
* The DLL is loading due to process initialization or a call to
* LoadLibrary.
*/
case DLL_PROCESS_ATTACH:
break;
/* The attached process creates a new thread. */
case DLL_THREAD_ATTACH:
break;
/* The thread of the attached process terminates. */
case DLL_THREAD_DETACH:
/*
* Disable DllMain() invocation on Thread creation/destruction
*/
DisableThreadLibraryCalls(hinstDLL);
isc_mem_initialize(); /* priority=101 */
isc_tls_initialize(); /* priority=102
isc_nm_initialized(); /* priority=103 */
break;
/*
* The DLL is unloading from a process due to
* process termination or a call to FreeLibrary.
* The DLL is unloading from a process due to process
* termination or a call to FreeLibrary.
*/
case DLL_PROCESS_DETACH:
isc_nm_shutdown(); /* priority=103 */
isc_tls_shutdown(); /* priority=102 */
isc_mem_shutdown(); /* priority=101 */
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
/*
* Calling DllMain when attaching/detaching process has been
* disabled.
*/
INSIST(0);
break;
default:
-1
View File
@@ -368,7 +368,6 @@ isc_mem_create
isc_mem_destroy
isc_mem_detach
isc_mem_getname
isc_mem_gettag
isc_mem_inuse
isc_mem_isovermem
isc_mem_maxinuse
+1 -1
View File
@@ -2506,7 +2506,7 @@ ns_clientmgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr,
for (i = 0; i < npools; i++) {
manager->mctxpool[i] = NULL;
isc_mem_create(&manager->mctxpool[i]);
isc_mem_setname(manager->mctxpool[i], "client", NULL);
isc_mem_setname(manager->mctxpool[i], "client");
}
manager->magic = MANAGER_MAGIC;