From f8dc519a043962c2f5b97d2353867866e54a95f9 Mon Sep 17 00:00:00 2001 From: Kirill Pinegin Date: Thu, 14 Nov 2019 15:33:40 +0300 Subject: [PATCH 1/8] add flags, add function declaration --- CMakeLists.txt | 6 ++++++ include/mimalloc-types.h | 4 ++++ include/mimalloc.h | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 443476f0..203da67b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ option(MI_USE_CXX "Use the C++ compiler to compile the library" OFF) option(MI_SECURE "Use security mitigations (like guard pages and randomization)" OFF) option(MI_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanism (Unix)" OFF) option(MI_BUILD_TESTS "Build test executables" ON) +option(MI_USER_CLEANUP "Enable mi_register_user_cleanup functionality" OFF) set(mi_install_dir "lib/mimalloc-${mi_version}") @@ -71,6 +72,11 @@ if(MI_SECURE MATCHES "ON") list(APPEND mi_defines MI_SECURE=2) endif() +if(MI_USER_CLEANUP MATCHES "ON") + message(STATUS "Enable mi_register_user_cleanup functionality (MI_USER_CLEANUP=ON)") + list(APPEND mi_defines MI_USER_CLEANUP=1) +endif() + if(MI_SEE_ASM MATCHES "ON") message(STATUS "Generate assembly listings (MI_SEE_ASM=ON)") list(APPEND mi_cflags -save-temps) diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 72fb7e7e..5fbb9ea5 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -29,6 +29,10 @@ terms of the MIT license. A copy of the license can be found in the file #define MI_SECURE 0 #endif +#if !defined(MI_USER_CLEANUP) +#define MI_USER_CLEANUP 0 +#endif + // Define MI_DEBUG as 1 for basic assert checks and statistics // set it to 2 to do internal asserts, // and to 3 to do extensive invariant checking. diff --git a/include/mimalloc.h b/include/mimalloc.h index b63ed79d..f63038e5 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -114,6 +114,11 @@ mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_fre typedef void (mi_output_fun)(const char* msg); mi_decl_export void mi_register_output(mi_output_fun* out) mi_attr_noexcept; +#if MI_USER_CLEANUP +typedef void (mi_cleanup_fun)(void* user_data, void* p, size_t size); +mi_decl_export void mi_register_user_cleanup(mi_cleanup_fun* out, void* user_data) mi_attr_noexcept; +#endif + mi_decl_export void mi_collect(bool force) mi_attr_noexcept; mi_decl_export int mi_version(void) mi_attr_noexcept; mi_decl_export void mi_stats_reset(void) mi_attr_noexcept; From bb3558100b5b41e7a682be7005f3f0832117c7ff Mon Sep 17 00:00:00 2001 From: Kirill Pinegin Date: Thu, 14 Nov 2019 16:25:36 +0300 Subject: [PATCH 2/8] implement user clean up --- include/mimalloc.h | 4 +--- src/os.c | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index f63038e5..194edb47 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -114,10 +114,8 @@ mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_fre typedef void (mi_output_fun)(const char* msg); mi_decl_export void mi_register_output(mi_output_fun* out) mi_attr_noexcept; -#if MI_USER_CLEANUP typedef void (mi_cleanup_fun)(void* user_data, void* p, size_t size); -mi_decl_export void mi_register_user_cleanup(mi_cleanup_fun* out, void* user_data) mi_attr_noexcept; -#endif +mi_decl_export void mi_register_user_cleanup(mi_cleanup_fun* cleanup, void* user_data) mi_attr_noexcept; mi_decl_export void mi_collect(bool force) mi_attr_noexcept; mi_decl_export int mi_version(void) mi_attr_noexcept; diff --git a/src/os.c b/src/os.c index 2ad0648f..4d08c7bd 100644 --- a/src/os.c +++ b/src/os.c @@ -177,6 +177,39 @@ void _mi_os_init() { } #endif +#if MI_USER_CLEANUP +static mi_cleanup_fun* user_cleanup = NULL; +static void* cleanup_udata = NULL; +static void _mi_call_user_cleanup(void* p, size_t size) +{ + if(user_cleanup) + user_cleanup(cleanup_udata, p, size); +#if (MI_DEBUG>1) + else + memset(start, 0, csize); +#endif +} +#else +static void _mi_call_user_cleanup(void* p, size_t size) +{ + (void)p; + (void)size; +#if (MI_DEBUG>1) + if (MI_SECURE==0) + memset(start, 0, csize); // pretend it is eagerly reset +#endif +} +#endif + +void mi_register_user_cleanup(mi_cleanup_fun* cleanup, void* user_data) +{ + (void)cleanup; + (void)user_data; +#if MI_USER_CLEANUP + user_cleanup = cleanup; + cleanup_udata = user_data; +#endif +} /* ----------------------------------------------------------- Raw allocation on Windows (VirtualAlloc) and Unix's (mmap). @@ -186,6 +219,7 @@ static bool mi_os_mem_free(void* addr, size_t size, bool was_committed, mi_stats { if (addr == NULL || size == 0 || _mi_os_is_huge_reserved(addr)) return true; bool err = false; + _mi_call_user_cleanup(addr, size); #if defined(_WIN32) err = (VirtualFree(addr, 0, MEM_RELEASE) == 0); #elif defined(__wasi__) @@ -687,11 +721,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) else _mi_stat_decrease(&stats->reset, csize); if (!reset) return true; // nothing to do on unreset! - #if (MI_DEBUG>1) - if (MI_SECURE==0) { - memset(start, 0, csize); // pretend it is eagerly reset - } - #endif + _mi_call_user_cleanup(start, size); #if defined(_WIN32) // Testing shows that for us (on `malloc-large`) MEM_RESET is 2x faster than DiscardVirtualMemory From c8eeb8cc253ccdb8aa8d12a166b96fb708dcac3b Mon Sep 17 00:00:00 2001 From: Kirill Pinegin Date: Mon, 18 Nov 2019 11:28:48 +0300 Subject: [PATCH 3/8] update readme --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 0d11db16..c803646c 100644 --- a/readme.md +++ b/readme.md @@ -39,6 +39,8 @@ Notable aspects of the design include: randomized allocation, encrypted free lists, etc. to protect against various heap vulnerabilities. The performance penalty is only around 3% on average over our benchmarks. +- __user function for clean up memory__: _mimalloc_ can be built with MI_USER_CLEANUP=ON flag. This mode + allows setup user function for memory clean up before it returned to system. - __first-class heaps__: efficiently create and use multiple heaps to allocate across different regions. A heap can be destroyed at once instead of deallocating each object separately. - __bounded__: it does not suffer from _blowup_ \[1\], has bounded worst-case allocation From d894e5362f89eb1d21bb6599924e07c55f68dcfe Mon Sep 17 00:00:00 2001 From: Kirill Pinegin Date: Mon, 18 Nov 2019 12:14:09 +0300 Subject: [PATCH 4/8] fix build errors --- src/os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/os.c b/src/os.c index 4d08c7bd..58381c0a 100644 --- a/src/os.c +++ b/src/os.c @@ -186,7 +186,7 @@ static void _mi_call_user_cleanup(void* p, size_t size) user_cleanup(cleanup_udata, p, size); #if (MI_DEBUG>1) else - memset(start, 0, csize); + memset(p, 0, size); #endif } #else @@ -196,7 +196,7 @@ static void _mi_call_user_cleanup(void* p, size_t size) (void)size; #if (MI_DEBUG>1) if (MI_SECURE==0) - memset(start, 0, csize); // pretend it is eagerly reset + memset(p, 0, size); // pretend it is eagerly reset #endif } #endif From af52fa48ef7f89ce34532c0a51883ba459464d04 Mon Sep 17 00:00:00 2001 From: Kirill Pinegin Date: Mon, 18 Nov 2019 12:19:38 +0300 Subject: [PATCH 5/8] fix warning with exception specification --- src/os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index 58381c0a..1aaceb1e 100644 --- a/src/os.c +++ b/src/os.c @@ -201,7 +201,7 @@ static void _mi_call_user_cleanup(void* p, size_t size) } #endif -void mi_register_user_cleanup(mi_cleanup_fun* cleanup, void* user_data) +void mi_register_user_cleanup(mi_cleanup_fun* cleanup, void* user_data) mi_attr_noexcept { (void)cleanup; (void)user_data; From 80dc7a3eb051f2c281995bb802710b08f61465ff Mon Sep 17 00:00:00 2001 From: Kirill Pinegin Date: Wed, 4 Dec 2019 10:20:08 +0300 Subject: [PATCH 6/8] fix cleanup size parameter --- src/os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index 0aed771a..341858be 100644 --- a/src/os.c +++ b/src/os.c @@ -723,7 +723,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats) else _mi_stat_decrease(&stats->reset, csize); if (!reset) return true; // nothing to do on unreset! - _mi_call_user_cleanup(start, size); + _mi_call_user_cleanup(start, csize); #if defined(_WIN32) // Testing shows that for us (on `malloc-large`) MEM_RESET is 2x faster than DiscardVirtualMemory From 8243f623aa1ffcb2a06b5fe8e7eb83fa571c7978 Mon Sep 17 00:00:00 2001 From: hardened-steel Date: Thu, 5 Dec 2019 12:10:16 +0300 Subject: [PATCH 7/8] fix segfault error in mi_os_mem_free if was_commited has value "false" then we can't access to memory at "addr" --- src/os.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index 341858be..3acd0dbc 100644 --- a/src/os.c +++ b/src/os.c @@ -219,7 +219,8 @@ static bool mi_os_mem_free(void* addr, size_t size, bool was_committed, mi_stats { if (addr == NULL || size == 0 || _mi_os_is_huge_reserved(addr)) return true; bool err = false; - _mi_call_user_cleanup(addr, size); + if(was_committed) + _mi_call_user_cleanup(addr, size); #if defined(_WIN32) err = (VirtualFree(addr, 0, MEM_RELEASE) == 0); #elif defined(__wasi__) From cfaa77887eef20386f8461b4870611aeaa1f0c66 Mon Sep 17 00:00:00 2001 From: Kirill Pinegin Date: Mon, 9 Dec 2019 16:07:12 +0300 Subject: [PATCH 8/8] fix cmake option description --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ed0a46de..9807301d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ option(MI_USE_CXX "Use the C++ compiler to compile the library" OFF) option(MI_SEE_ASM "Generate assembly files" OFF) option(MI_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanism (Unix)" OFF) option(MI_BUILD_TESTS "Build test executables" ON) -option(MI_USER_CLEANUP "Enable mi_register_user_cleanup functionality" OFF) +option(MI_USER_CLEANUP "Enable user defined functionality for custom memory clean function" OFF) option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) set(mi_sources