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
This commit is contained in:
Ondřej Surý
2021-02-03 18:36:13 +01:00
committed by Ondřej Surý
parent c7392f92ea
commit dcaa3a785e
4 changed files with 102 additions and 0 deletions
+21
View File
@@ -604,6 +604,27 @@ 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)
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);
ISC_LANG_ENDDECLS
#endif /* ISC_MEM_H */
+17
View File
@@ -48,6 +48,14 @@
#define ISC_NONSTRING
#endif /* __GNUC__ */
#if __GNUC__
#define ISC_CONSTRUCTOR(priority) __attribute__((constructor(priority)))
#define ISC_DESTRUCTOR(priority) __attribute__((destructor(priority)))
#else
#define ISC_CONSTRUCTOR(priority)
#define ISC_DESTRUCTOR(priority)
#endif
/*%
* The opposite: silent warnings about stored values which are never read.
*/
@@ -340,6 +348,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
*/
+57
View File
@@ -2520,3 +2520,60 @@ isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
UNUSED(file);
#endif /* if ISC_MEM_TRACKLINES */
}
/*
* Routines using default memory context
*/
static isc_mem_t *isc__mem_mctx = NULL;
void
isc__mem_initialize(void);
void
isc__mem_shutdown(void);
ISC_CONSTRUCTOR(101)
void
isc__mem_initialize(void) {
REQUIRE(isc__mem_mctx == NULL);
isc_mem_create(&isc__mem_mctx);
isc_mem_setname(isc__mem_mctx, "default", NULL);
}
ISC_DESTRUCTOR(101)
void
isc__mem_shutdown(void) {
REQUIRE(isc__mem_mctx != NULL);
isc_mem_destroy(&isc__mem_mctx);
isc_mem_checkdestroyed(stderr);
}
void *
isc__malloc(size_t size FLARG) {
return (isc__mem_allocate(isc__mem_mctx, size FLARG_PASS));
}
void *
isc__calloc(size_t num, size_t size FLARG) {
size_t numsize;
ISC_MUL_OVERFLOW(num, size, &numsize);
void *ptr = isc__mem_allocate(isc__mem_mctx, numsize FLARG_PASS);
memset(ptr, 0, numsize);
return (ptr);
}
void *
isc__realloc(void *ptr, size_t size FLARG) {
return (isc__mem_reallocate(isc__mem_mctx, ptr, size FLARG_PASS));
}
void
isc__free(void *ptr FLARG) {
isc__mem_free(isc__mem_mctx, ptr FLARG_PASS);
}
char *
isc__strdup(const char *s1 FLARG) {
return (isc__mem_strdup(isc__mem_mctx, s1 FLARG_PASS));
}
+7
View File
@@ -12,6 +12,11 @@
#include <stdio.h>
#include <windows.h>
void
isc__mem_initialize(void);
void
isc__mem_shutdown(void);
/*
* Called when we enter the DLL
*/
@@ -27,6 +32,7 @@ __declspec(dllexport) BOOL WINAPI
* Disable DllMain() invocation on Thread creation/destruction
*/
DisableThreadLibraryCalls(hinstDLL);
isc__mem_initialize(); /* priority=101 */
break;
/*
@@ -34,6 +40,7 @@ __declspec(dllexport) BOOL WINAPI
* termination or a call to FreeLibrary.
*/
case DLL_PROCESS_DETACH:
isc__mem_shutdown(); /* priority=101 */
break;
case DLL_THREAD_ATTACH: