From d4363bbaf852ed089e850cb0931ab50fb9c5f06d Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Tue, 28 Apr 2020 18:12:43 +0300 Subject: [PATCH 01/10] Add possibility to selectively enable / disable builing of different targets. --- CMakeLists.txt | 127 +++++++++++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e37b5083..94bb6e1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,9 @@ option(MI_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanis option(MI_BUILD_TESTS "Build test executables" ON) option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) option(MI_PADDING "Enable padding to detect heap block overflow (only in debug mode)" ON) +option(MI_BUILD_SHARED "Build shared library" ON) +option(MI_BUILD_STATIC "Build static library" ON) +option(MI_BUILD_OBJECT "Build object" ON) include("cmake/mimalloc-config-version.cmake") @@ -180,52 +183,62 @@ message(STATUS "") # ----------------------------------------------------------------------------- # shared library -add_library(mimalloc SHARED ${mi_sources}) -set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} OUTPUT_NAME ${mi_basename} ) -target_compile_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT) -target_compile_options(mimalloc PRIVATE ${mi_cflags}) -target_link_libraries(mimalloc PUBLIC ${mi_libraries}) -target_include_directories(mimalloc PUBLIC - $ - $ -) -if(WIN32) - # On windows copy the mimalloc redirection dll too. - target_link_libraries(mimalloc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect.lib) - add_custom_command(TARGET mimalloc POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect.dll" $ - COMMENT "Copy mimalloc-redirect.dll to output directory") +if(MI_BUILD_SHARED) + message(STATUS "Shared library will be built") + + add_library(mimalloc SHARED ${mi_sources}) + set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} OUTPUT_NAME ${mi_basename} ) + target_compile_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT) + target_compile_options(mimalloc PRIVATE ${mi_cflags}) + target_link_libraries(mimalloc PUBLIC ${mi_libraries}) + target_include_directories(mimalloc PUBLIC + $ + $ + ) + if(WIN32) + # On windows copy the mimalloc redirection dll too. + target_link_libraries(mimalloc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect.lib) + add_custom_command(TARGET mimalloc POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect.dll" $ + COMMENT "Copy mimalloc-redirect.dll to output directory") + endif() + + install(TARGETS mimalloc EXPORT mimalloc DESTINATION ${mi_install_dir} LIBRARY) + install(EXPORT mimalloc DESTINATION ${mi_install_dir}/cmake) endif() # static library -add_library(mimalloc-static STATIC ${mi_sources}) -target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB) -target_compile_options(mimalloc-static PRIVATE ${mi_cflags}) -target_link_libraries(mimalloc-static PUBLIC ${mi_libraries}) -target_include_directories(mimalloc-static PUBLIC - $ - $ -) -if(WIN32) - # When building both static and shared libraries on Windows, a static library should use a - # different output name to avoid the conflict with the import library of a shared one. - string(REPLACE "mimalloc" "mimalloc-static" mi_output_name ${mi_basename}) - set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_output_name}) -else() - set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename}) +if (MI_BUILD_STATIC) + message(STATUS "Static library will be built") + + add_library(mimalloc-static STATIC ${mi_sources}) + target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB) + target_compile_options(mimalloc-static PRIVATE ${mi_cflags}) + target_link_libraries(mimalloc-static PUBLIC ${mi_libraries}) + target_include_directories(mimalloc-static PUBLIC + $ + $ + ) + if(WIN32 AND MI_BUILD_SHARED) + # When building both static and shared libraries on Windows, a static library should use a + # different output name to avoid the conflict with the import library of a shared one. + string(REPLACE "mimalloc" "mimalloc-static" mi_output_name ${mi_basename}) + set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_output_name}) + else() + set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename}) + endif() + + install(TARGETS mimalloc-static EXPORT mimalloc DESTINATION ${mi_install_dir}) endif() -# install static and shared library, and the include files -install(TARGETS mimalloc EXPORT mimalloc DESTINATION ${mi_install_dir} LIBRARY) -install(TARGETS mimalloc-static EXPORT mimalloc DESTINATION ${mi_install_dir}) +# install include files install(FILES include/mimalloc.h DESTINATION ${mi_install_dir}/include) install(FILES include/mimalloc-override.h DESTINATION ${mi_install_dir}/include) install(FILES include/mimalloc-new-delete.h DESTINATION ${mi_install_dir}/include) install(FILES cmake/mimalloc-config.cmake DESTINATION ${mi_install_dir}/cmake) install(FILES cmake/mimalloc-config-version.cmake DESTINATION ${mi_install_dir}/cmake) -install(EXPORT mimalloc DESTINATION ${mi_install_dir}/cmake) -if(NOT WIN32) +if(NOT WIN32 AND MI_BUILD_SHARED) # install a symlink in the /usr/local/lib to the versioned library set(mi_symlink "${CMAKE_SHARED_MODULE_PREFIX}${mi_basename}${CMAKE_SHARED_LIBRARY_SUFFIX}") set(mi_soname "mimalloc-${mi_version}/${mi_symlink}.${mi_version}") @@ -234,22 +247,26 @@ if(NOT WIN32) endif() # single object file for more predictable static overriding -add_library(mimalloc-obj OBJECT src/static.c) -target_compile_definitions(mimalloc-obj PRIVATE ${mi_defines}) -target_compile_options(mimalloc-obj PRIVATE ${mi_cflags}) -target_include_directories(mimalloc-obj PUBLIC - $ - $ -) +if (MI_BUILD_OBJECT) + message(STATUS "Library object will be built") -# the following seems to lead to cmake warnings/errors on some systems, disable for now :-( -# install(TARGETS mimalloc-obj EXPORT mimalloc DESTINATION ${mi_install_dir}) + add_library(mimalloc-obj OBJECT src/static.c) + target_compile_definitions(mimalloc-obj PRIVATE ${mi_defines}) + target_compile_options(mimalloc-obj PRIVATE ${mi_cflags}) + target_include_directories(mimalloc-obj PUBLIC + $ + $ + ) -# the FILES expression can also be: $ -# but that fails cmake versions less than 3.10 so we leave it as is for now -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/mimalloc-obj.dir/src/static.c${CMAKE_C_OUTPUT_EXTENSION} - DESTINATION ${mi_install_dir} - RENAME ${mi_basename}${CMAKE_C_OUTPUT_EXTENSION} ) + # the following seems to lead to cmake warnings/errors on some systems, disable for now :-( + # install(TARGETS mimalloc-obj EXPORT mimalloc DESTINATION ${mi_install_dir}) + + # the FILES expression can also be: $ + # but that fails cmake versions less than 3.10 so we leave it as is for now + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/mimalloc-obj.dir/src/static.c${CMAKE_C_OUTPUT_EXTENSION} + DESTINATION ${mi_install_dir} + RENAME ${mi_basename}${CMAKE_C_OUTPUT_EXTENSION} ) +endif() # ----------------------------------------------------------------------------- # API surface testing @@ -277,10 +294,16 @@ endif() # Set override properties # ----------------------------------------------------------------------------- if (MI_OVERRIDE MATCHES "ON") - target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) + if (MI_BUILD_SHARED) + target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) + endif() if(NOT WIN32) # It is only possible to override malloc on Windows when building as a DLL. - target_compile_definitions(mimalloc-static PRIVATE MI_MALLOC_OVERRIDE) - target_compile_definitions(mimalloc-obj PRIVATE MI_MALLOC_OVERRIDE) + if (MI_BUILD_STATIC) + target_compile_definitions(mimalloc-static PRIVATE MI_MALLOC_OVERRIDE) + endif() + if (MI_BUILD_OBJECT) + target_compile_definitions(mimalloc-obj PRIVATE MI_MALLOC_OVERRIDE) + endif() endif() endif() From fdd1cd821acd432dca43c1a82707bcdccd8bb0c9 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Wed, 29 Apr 2020 02:10:11 +0300 Subject: [PATCH 02/10] In OOM case try to force collect memory and retry the allocation. --- src/page.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/page.c b/src/page.c index 2903b258..944c16fb 100644 --- a/src/page.c +++ b/src/page.c @@ -790,6 +790,24 @@ static mi_page_t* mi_huge_page_alloc(mi_heap_t* heap, size_t size) { } +static mi_page_t *_mi_find_page(mi_heap_t* heap, size_t size) mi_attr_noexcept { + // huge allocation? + const size_t req_size = size - MI_PADDING_SIZE; // correct for padding_size in case of an overflow on `size` + if (mi_unlikely(req_size > (MI_LARGE_OBJ_SIZE_MAX - MI_PADDING_SIZE) )) { + if (mi_unlikely(req_size > PTRDIFF_MAX)) { // we don't allocate more than PTRDIFF_MAX (see ) + _mi_error_message(EOVERFLOW, "allocation request is too large (%zu b requested)\n", req_size); + return NULL; + } + else { + return mi_huge_page_alloc(heap,size); + } + } + + // otherwise find a page with free blocks in our size segregated queues + mi_assert_internal(size >= MI_PADDING_SIZE); + return mi_find_free_page(heap,size); +} + // Generic allocation routine if the fast path (`alloc.c:mi_page_malloc`) does not succeed. // Note: in debug mode the size includes MI_PADDING_SIZE and might have overflowed. void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept @@ -809,23 +827,12 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept // free delayed frees from other threads _mi_heap_delayed_free(heap); - // huge allocation? - mi_page_t* page; - const size_t req_size = size - MI_PADDING_SIZE; // correct for padding_size in case of an overflow on `size` - if (mi_unlikely(req_size > (MI_LARGE_OBJ_SIZE_MAX - MI_PADDING_SIZE) )) { - if (mi_unlikely(req_size > PTRDIFF_MAX)) { // we don't allocate more than PTRDIFF_MAX (see ) - _mi_error_message(EOVERFLOW, "allocation request is too large (%zu b requested)\n", req_size); - return NULL; - } - else { - page = mi_huge_page_alloc(heap,size); - } - } - else { - // otherwise find a page with free blocks in our size segregated queues - mi_assert_internal(size >= MI_PADDING_SIZE); - page = mi_find_free_page(heap,size); + mi_page_t* page = _mi_find_page(heap, size); + if (mi_unlikely(page == NULL)) { // out of memory, try to collect and retry allocation + mi_heap_collect(heap, true /* force */); + page = _mi_find_page(heap, size); } + if (mi_unlikely(page == NULL)) { // out of memory _mi_error_message(ENOMEM, "cannot allocate memory (%zu bytes requested)\n", size); return NULL; From fd9faee5d4a7f7879db14501c123e76ee2a95726 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 4 May 2020 11:01:11 -0700 Subject: [PATCH 03/10] update cmake with nicer message which targets are build --- CMakeLists.txt | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66626b3f..e37efcb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,22 +4,22 @@ project(libmimalloc C CXX) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) -option(MI_OVERRIDE "Override the standard malloc interface" ON) -option(MI_DEBUG_FULL "Use full internal heap invariant checking in DEBUG mode" OFF) option(MI_SECURE "Use full security mitigations (like guard pages, allocation randomization, double-free mitigation, and free-list corruption detection)" OFF) -option(MI_USE_CXX "Use the C++ compiler to compile the library" OFF) +option(MI_DEBUG_FULL "Use full internal heap invariant checking in DEBUG mode (expensive)" OFF) +option(MI_PADDING "Enable padding to detect heap block overflow (used only in DEBUG mode)" ON) +option(MI_OVERRIDE "Override the standard malloc interface (e.g. define entry points for malloc() etc)" ON) +option(MI_XMALLOC "Enable abort() call on memory allocation failure by default" OFF) +option(MI_SHOW_ERRORS "Show error and warning messages by default (only enabled by default in DEBUG mode)" OFF) +option(MI_USE_CXX "Use the C++ compiler to compile the library (instead of the C compiler)" OFF) option(MI_SEE_ASM "Generate assembly files" OFF) option(MI_INTERPOSE "Use interpose to override standard malloc on macOS" ON) option(MI_OSX_ZONE "Use malloc zone to override standard malloc on macOS" OFF) # enables interpose as well option(MI_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanism (Unix)" OFF) -option(MI_BUILD_TESTS "Build test executables" ON) -option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) -option(MI_PADDING "Enable padding to detect heap block overflow (only in debug mode)" ON) option(MI_BUILD_SHARED "Build shared library" ON) option(MI_BUILD_STATIC "Build static library" ON) -option(MI_BUILD_OBJECT "Build object" ON) -option(MI_XMALLOC "Enable abort() call on memory allocation failure by default" OFF) -option(MI_SHOW_ERRORS "Show error and warning messages by default" OFF) +option(MI_BUILD_OBJECT "Build object library" ON) +option(MI_BUILD_TESTS "Build test executables" ON) +option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) include("cmake/mimalloc-config-version.cmake") @@ -185,10 +185,23 @@ string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LC) if(NOT(CMAKE_BUILD_TYPE_LC MATCHES "^(release|relwithdebinfo|minsizerel)$")) set(mi_basename "${mi_basename}-${CMAKE_BUILD_TYPE_LC}") #append build type (e.g. -debug) if not a release version endif() +if(MI_BUILD_SHARED) + list(APPEND mi_build_targets "shared") +endif() +if(MI_BUILD_STATIC) + list(APPEND mi_build_targets "static") +endif() +if(MI_BUILD_OBJECT) + list(APPEND mi_build_targets "object") +endif() +if(MI_BUILD_TESTS) + list(APPEND mi_build_targets "tests") +endif() message(STATUS "") message(STATUS "Library base name: ${mi_basename}") message(STATUS "Build type : ${CMAKE_BUILD_TYPE_LC}") message(STATUS "Install directory: ${mi_install_dir}") +message(STATUS "Build targets : ${mi_build_targets}") message(STATUS "") # ----------------------------------------------------------------------------- @@ -197,8 +210,6 @@ message(STATUS "") # shared library if(MI_BUILD_SHARED) - message(STATUS "Shared library will be built") - add_library(mimalloc SHARED ${mi_sources}) set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} OUTPUT_NAME ${mi_basename} ) target_compile_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT) @@ -222,8 +233,6 @@ endif() # static library if (MI_BUILD_STATIC) - message(STATUS "Static library will be built") - add_library(mimalloc-static STATIC ${mi_sources}) set_property(TARGET mimalloc-static PROPERTY POSITION_INDEPENDENT_CODE ON) target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB) @@ -262,8 +271,6 @@ endif() # single object file for more predictable static overriding if (MI_BUILD_OBJECT) - message(STATUS "Library object will be built") - add_library(mimalloc-obj OBJECT src/static.c) set_property(TARGET mimalloc-obj PROPERTY POSITION_INDEPENDENT_CODE ON) target_compile_definitions(mimalloc-obj PRIVATE ${mi_defines}) @@ -279,7 +286,7 @@ if (MI_BUILD_OBJECT) # the FILES expression can also be: $ # but that fails cmake versions less than 3.10 so we leave it as is for now install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/mimalloc-obj.dir/src/static.c${CMAKE_C_OUTPUT_EXTENSION} - DESTINATION ${mi_install_dir} + DESTINATION ${mi_install_dir} RENAME ${mi_basename}${CMAKE_C_OUTPUT_EXTENSION} ) endif() From 7c24edfeb02bd2f872d959771dfebb3a647b2942 Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 4 May 2020 14:31:32 -0700 Subject: [PATCH 04/10] add thread-id check for thread local FLS callbacks on Windows with static linking; found by @jasongibson --- src/init.c | 38 ++++++++++++++++------------ test/main-override.cpp | 56 +++++++++++++++++++++++++++++++++--------- 2 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/init.c b/src/init.c index 6b62e888..2ccc0d83 100644 --- a/src/init.c +++ b/src/init.c @@ -216,23 +216,25 @@ static bool _mi_heap_done(mi_heap_t* heap) { heap = heap->tld->heap_backing; if (!mi_heap_is_initialized(heap)) return false; - - // delete all non-backing heaps in this thread - mi_heap_t* curr = heap->tld->heaps; - while (curr != NULL) { - mi_heap_t* next = curr->next; // save `next` as `curr` will be freed - if (curr != heap) { - mi_assert_internal(!mi_heap_is_backing(curr)); - mi_heap_delete(curr); + // check thread-id as on Windows shutdown with FLS the main (exit) thread may call this on thread-local heaps + if (heap->thread_id == _mi_thread_id()) { + // delete all non-backing heaps in this thread + mi_heap_t* curr = heap->tld->heaps; + while (curr != NULL) { + mi_heap_t* next = curr->next; // save `next` as `curr` will be freed + if (curr != heap) { + mi_assert_internal(!mi_heap_is_backing(curr)); + mi_heap_delete(curr); + } + curr = next; } - curr = next; - } - mi_assert_internal(heap->tld->heaps == heap && heap->next == NULL); - mi_assert_internal(mi_heap_is_backing(heap)); + mi_assert_internal(heap->tld->heaps == heap && heap->next == NULL); + mi_assert_internal(mi_heap_is_backing(heap)); - // collect if not the main thread - if (heap != &_mi_heap_main) { - _mi_heap_collect_abandon(heap); + // collect if not the main thread + if (heap != &_mi_heap_main) { + _mi_heap_collect_abandon(heap); + } } // merge stats @@ -240,7 +242,7 @@ static bool _mi_heap_done(mi_heap_t* heap) { // free if not the main thread if (heap != &_mi_heap_main) { - mi_assert_internal(heap->tld->segments.count == 0); + mi_assert_internal(heap->tld->segments.count == 0 || heap->thread_id != _mi_thread_id()); _mi_os_free(heap, sizeof(mi_thread_data_t), &_mi_stats_main); } #if 0 @@ -294,6 +296,10 @@ static void _mi_thread_done(mi_heap_t* default_heap); #endif static DWORD mi_fls_key = (DWORD)(-1); static void NTAPI mi_fls_done(PVOID value) { + if (mi_fls_key != -1 && _mi_is_main_thread()) { + FlsSetValue(mi_fls_key, NULL); // null out once to prevent recursion on the main thread + mi_fls_key = -1; + } if (value!=NULL) _mi_thread_done((mi_heap_t*)value); } #elif defined(MI_USE_PTHREADS) diff --git a/test/main-override.cpp b/test/main-override.cpp index 734e4c94..8743fd0f 100644 --- a/test/main-override.cpp +++ b/test/main-override.cpp @@ -7,11 +7,15 @@ #include #include #include +#include +#include #include #include #include +#include + #ifdef _WIN32 #include static void msleep(unsigned long msecs) { Sleep(msecs); } @@ -25,14 +29,16 @@ void heap_no_delete(); // issue #202 void heap_late_free(); // issue #204 void padding_shrink(); // issue #209 void various_tests(); +void test_mt_shutdown(); int main() { mi_stats_reset(); // ignore earlier allocations heap_thread_free_large(); - heap_no_delete(); - heap_late_free(); - padding_shrink(); + heap_no_delete(); + heap_late_free(); + padding_shrink(); various_tests(); + //test_mt_shutdown(); mi_stats_print(NULL); return 0; } @@ -53,20 +59,20 @@ public: }; -void various_tests() { +void various_tests() { atexit(free_p); void* p1 = malloc(78); - void* p2 = mi_malloc_aligned(16,24); - free(p1); + void* p2 = mi_malloc_aligned(16, 24); + free(p1); p1 = malloc(8); char* s = mi_strdup("hello\n"); - + //char* s = _strdup("hello\n"); //char* buf = NULL; //size_t len; //_dupenv_s(&buf,&len,"MIMALLOC_VERBOSE"); //mi_free(buf); - + mi_free(p2); p2 = malloc(16); p1 = realloc(p1, 32); @@ -76,7 +82,7 @@ void various_tests() { Test* t = new Test(42); delete t; t = new (std::nothrow) Test(42); - delete t; + delete t; } class Static { @@ -105,7 +111,7 @@ bool test_stl_allocator1() { struct some_struct { int i; int j; double z; }; -bool test_stl_allocator2() { +bool test_stl_allocator2() { std::vector > vec; vec.push_back(some_struct()); vec.pop_back(); @@ -117,13 +123,13 @@ bool test_stl_allocator2() { // Issue #202 void heap_no_delete_worker() { mi_heap_t* heap = mi_heap_new(); - void* q = mi_heap_malloc(heap,1024); + void* q = mi_heap_malloc(heap, 1024); // mi_heap_delete(heap); // uncomment to prevent assertion } void heap_no_delete() { auto t1 = std::thread(heap_no_delete_worker); - t1.join(); + t1.join(); } @@ -173,3 +179,29 @@ void heap_thread_free_large() { t1.join(); } } + + + +void test_mt_shutdown() +{ + const int threads = 5; + std::vector< std::future< std::vector< char* > > > ts; + + auto fn = [&]() + { + std::vector< char* > ps; + ps.reserve(1000); + for (int i = 0; i < 1000; i++) + ps.emplace_back(new char[1]); + return ps; + }; + + for (int i = 0; i < threads; i++) + ts.emplace_back(std::async(std::launch::async, fn)); + + for (auto& f : ts) + for (auto& p : f.get()) + delete[] p; + + std::cout << "done" << std::endl; +} From a278db940bb25c294c60cd258b4051df7ae5187f Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 5 May 2020 10:10:46 -0700 Subject: [PATCH 05/10] improve thread-id check for thread local FLS callbacks on Windows with static linking --- src/init.c | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/init.c b/src/init.c index 2ccc0d83..132043e8 100644 --- a/src/init.c +++ b/src/init.c @@ -216,26 +216,24 @@ static bool _mi_heap_done(mi_heap_t* heap) { heap = heap->tld->heap_backing; if (!mi_heap_is_initialized(heap)) return false; - // check thread-id as on Windows shutdown with FLS the main (exit) thread may call this on thread-local heaps - if (heap->thread_id == _mi_thread_id()) { - // delete all non-backing heaps in this thread - mi_heap_t* curr = heap->tld->heaps; - while (curr != NULL) { - mi_heap_t* next = curr->next; // save `next` as `curr` will be freed - if (curr != heap) { - mi_assert_internal(!mi_heap_is_backing(curr)); - mi_heap_delete(curr); - } - curr = next; - } - mi_assert_internal(heap->tld->heaps == heap && heap->next == NULL); - mi_assert_internal(mi_heap_is_backing(heap)); - - // collect if not the main thread - if (heap != &_mi_heap_main) { - _mi_heap_collect_abandon(heap); + // delete all non-backing heaps in this thread + mi_heap_t* curr = heap->tld->heaps; + while (curr != NULL) { + mi_heap_t* next = curr->next; // save `next` as `curr` will be freed + if (curr != heap) { + mi_assert_internal(!mi_heap_is_backing(curr)); + mi_heap_delete(curr); } + curr = next; } + mi_assert_internal(heap->tld->heaps == heap && heap->next == NULL); + mi_assert_internal(mi_heap_is_backing(heap)); + + // collect if not the main thread + if (heap != &_mi_heap_main) { + _mi_heap_collect_abandon(heap); + } + // merge stats _mi_stats_done(&heap->tld->stats); @@ -296,10 +294,6 @@ static void _mi_thread_done(mi_heap_t* default_heap); #endif static DWORD mi_fls_key = (DWORD)(-1); static void NTAPI mi_fls_done(PVOID value) { - if (mi_fls_key != -1 && _mi_is_main_thread()) { - FlsSetValue(mi_fls_key, NULL); // null out once to prevent recursion on the main thread - mi_fls_key = -1; - } if (value!=NULL) _mi_thread_done((mi_heap_t*)value); } #elif defined(MI_USE_PTHREADS) @@ -361,12 +355,16 @@ void mi_thread_done(void) mi_attr_noexcept { } static void _mi_thread_done(mi_heap_t* heap) { + // check thread-id as on Windows shutdown with FLS the main (exit) thread may call this on thread-local heaps... + if (heap->thread_id != _mi_thread_id()) return; + // stats if (!_mi_is_main_thread() && mi_heap_is_initialized(heap)) { _mi_stat_decrease(&heap->tld->stats.threads, 1); } + // abandon the thread local heap - if (_mi_heap_done(heap)) return; // returns true if already ran + if (_mi_heap_done(heap)) return; // returns true if already ran } void _mi_heap_set_default_direct(mi_heap_t* heap) { From 29cb8f369a6d42b24619f0a89cefbcdb9a35126b Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 5 May 2020 10:24:16 -0700 Subject: [PATCH 06/10] slight cleanup of f10ba4fa, #239 --- src/page.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/page.c b/src/page.c index d28c5204..08aa88c7 100644 --- a/src/page.c +++ b/src/page.c @@ -785,7 +785,9 @@ static mi_page_t* mi_huge_page_alloc(mi_heap_t* heap, size_t size) { } -static mi_page_t *_mi_find_page(mi_heap_t* heap, size_t size) mi_attr_noexcept { +// Allocate a page +// Note: in debug mode the size includes MI_PADDING_SIZE and might have overflowed. +static mi_page_t* mi_find_page(mi_heap_t* heap, size_t size) mi_attr_noexcept { // huge allocation? const size_t req_size = size - MI_PADDING_SIZE; // correct for padding_size in case of an overflow on `size` if (mi_unlikely(req_size > (MI_LARGE_OBJ_SIZE_MAX - MI_PADDING_SIZE) )) { @@ -797,10 +799,11 @@ static mi_page_t *_mi_find_page(mi_heap_t* heap, size_t size) mi_attr_noexcept { return mi_huge_page_alloc(heap,size); } } - - // otherwise find a page with free blocks in our size segregated queues - mi_assert_internal(size >= MI_PADDING_SIZE); - return mi_find_free_page(heap,size); + else { + // otherwise find a page with free blocks in our size segregated queues + mi_assert_internal(size >= MI_PADDING_SIZE); + return mi_find_free_page(heap, size); + } } // Generic allocation routine if the fast path (`alloc.c:mi_page_malloc`) does not succeed. @@ -822,10 +825,11 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept // free delayed frees from other threads _mi_heap_delayed_free(heap); - mi_page_t* page = _mi_find_page(heap, size); - if (mi_unlikely(page == NULL)) { // out of memory, try to collect and retry allocation + // find (or allocate) a page of the right size + mi_page_t* page = mi_find_page(heap, size); + if (mi_unlikely(page == NULL)) { // first time out of memory, try to collect and retry the allocation once more mi_heap_collect(heap, true /* force */); - page = _mi_find_page(heap, size); + page = mi_find_page(heap, size); } if (mi_unlikely(page == NULL)) { // out of memory From 775e1bfd7af7c3802b321dc4d69863fc22bb100a Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 5 May 2020 10:38:25 -0700 Subject: [PATCH 07/10] allow uploading artifacts for master branch --- azure-pipelines.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c81e31bd..954ec15d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -40,8 +40,8 @@ jobs: cd $(BuildType) ctest displayName: CTest -# - upload: $(Build.SourcesDirectory)/$(BuildType) -# artifact: mimalloc-windows-$(BuildType) + - upload: $(Build.SourcesDirectory)/$(BuildType) + artifact: mimalloc-windows-$(BuildType) - job: displayName: Linux @@ -99,8 +99,8 @@ jobs: displayName: Make - script: make test -C $(BuildType) displayName: CTest -# - upload: $(Build.SourcesDirectory)/$(BuildType) -# artifact: mimalloc-ubuntu-$(BuildType) + - upload: $(Build.SourcesDirectory)/$(BuildType) + artifact: mimalloc-ubuntu-$(BuildType) - job: displayName: macOS @@ -127,5 +127,5 @@ jobs: displayName: Make - script: make test -C $(BuildType) displayName: CTest -# - upload: $(Build.SourcesDirectory)/$(BuildType) -# artifact: mimalloc-macos-$(BuildType) + - upload: $(Build.SourcesDirectory)/$(BuildType) + artifact: mimalloc-macos-$(BuildType) From e6c7b778fb53663985e0a36016a3a087af71d783 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 5 May 2020 10:45:10 -0700 Subject: [PATCH 08/10] update readme for v1.6.3 --- readme.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index fd600763..7ec20d72 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ mimalloc (pronounced "me-malloc") is a general purpose allocator with excellent [performance](#performance) characteristics. Initially developed by Daan Leijen for the run-time systems of the [Koka](https://github.com/koka-lang/koka) and [Lean](https://github.com/leanprover/lean) languages. -Latest release:`v1.6.2` (2020-04-20). +Latest release:`v1.6.3` (2020-05-05). It is a drop-in replacement for `malloc` and can be used in other programs without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as: @@ -57,6 +57,8 @@ Enjoy! ### Releases +* 2020-05-05, `v1.6.3`: stable release 1.6: improved behavior in out-of-memory situations, improved malloc zones on macOS, + build PIC static libraries by default, add option to abort on out-of-memory, line buffered statistics. * 2020-04-20, `v1.6.2`: stable release 1.6: fix compilation on Android, MingW, Raspberry, and Conda, stability fix for Windows 7, fix multiple mimalloc instances in one executable, fix `strnlen` overload, fix aligned debug padding. @@ -262,19 +264,19 @@ to make mimalloc more robust against exploits. In particular: - All internal mimalloc pages are surrounded by guard pages and the heap metadata is behind a guard page as well (so a buffer overflow exploit cannot reach into the metadata), -- All free list pointers are - [encoded](https://github.com/microsoft/mimalloc/blob/783e3377f79ee82af43a0793910a9f2d01ac7863/include/mimalloc-internal.h#L396) +- All free list pointers are + [encoded](https://github.com/microsoft/mimalloc/blob/783e3377f79ee82af43a0793910a9f2d01ac7863/include/mimalloc-internal.h#L396) with per-page keys which is used both to prevent overwrites with a known pointer, as well as to detect heap corruption, - Double free's are detected (and ignored), -- The free lists are initialized in a random order and allocation randomly chooses between extension and reuse within a page to - mitigate against attacks that rely on a predicable allocation order. Similarly, the larger heap blocks allocated by mimalloc +- The free lists are initialized in a random order and allocation randomly chooses between extension and reuse within a page to + mitigate against attacks that rely on a predicable allocation order. Similarly, the larger heap blocks allocated by mimalloc from the OS are also address randomized. As always, evaluate with care as part of an overall security strategy as all of the above are mitigations but not guarantees. ## Debug Mode -When _mimalloc_ is built using debug mode, various checks are done at runtime to catch development errors. +When _mimalloc_ is built using debug mode, various checks are done at runtime to catch development errors. - Statistics are maintained in detail for each object size. They can be shown using `MIMALLOC_SHOW_STATS=1` at runtime. - All objects have padding at the end to detect (byte precise) heap block overflows. From ccb51c6abeebeb2105cb74bad4f4a5ad9c873747 Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 5 May 2020 10:46:39 -0700 Subject: [PATCH 09/10] disable artifact uploading in dev --- azure-pipelines.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 954ec15d..c81e31bd 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -40,8 +40,8 @@ jobs: cd $(BuildType) ctest displayName: CTest - - upload: $(Build.SourcesDirectory)/$(BuildType) - artifact: mimalloc-windows-$(BuildType) +# - upload: $(Build.SourcesDirectory)/$(BuildType) +# artifact: mimalloc-windows-$(BuildType) - job: displayName: Linux @@ -99,8 +99,8 @@ jobs: displayName: Make - script: make test -C $(BuildType) displayName: CTest - - upload: $(Build.SourcesDirectory)/$(BuildType) - artifact: mimalloc-ubuntu-$(BuildType) +# - upload: $(Build.SourcesDirectory)/$(BuildType) +# artifact: mimalloc-ubuntu-$(BuildType) - job: displayName: macOS @@ -127,5 +127,5 @@ jobs: displayName: Make - script: make test -C $(BuildType) displayName: CTest - - upload: $(Build.SourcesDirectory)/$(BuildType) - artifact: mimalloc-macos-$(BuildType) +# - upload: $(Build.SourcesDirectory)/$(BuildType) +# artifact: mimalloc-macos-$(BuildType) From cefc930f723ffdcb8b730655bfd25a389f790bbe Mon Sep 17 00:00:00 2001 From: daan Date: Tue, 5 May 2020 10:47:46 -0700 Subject: [PATCH 10/10] bump version to 1.6.4 for further development --- include/mimalloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mimalloc.h b/include/mimalloc.h index 0af04a94..f44f6d9a 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -8,7 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file #ifndef MIMALLOC_H #define MIMALLOC_H -#define MI_MALLOC_VERSION 163 // major + 2 digits minor +#define MI_MALLOC_VERSION 164 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes