merge from dev

This commit is contained in:
daan 2020-05-05 10:54:59 -07:00
commit 53aa46890a
6 changed files with 177 additions and 98 deletions

View file

@ -4,19 +4,22 @@ project(libmimalloc C CXX)
set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17) 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_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_SEE_ASM "Generate assembly files" OFF)
option(MI_INTERPOSE "Use interpose to override standard malloc on macOS" ON) 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_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_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanism (Unix)" OFF)
option(MI_BUILD_SHARED "Build shared library" ON)
option(MI_BUILD_STATIC "Build static library" ON)
option(MI_BUILD_OBJECT "Build object library" ON)
option(MI_BUILD_TESTS "Build test executables" 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) 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_XMALLOC "Enable abort() call on memory allocation failure by default" OFF)
option(MI_SHOW_ERRORS "Show error and warning messages by default" OFF)
include("cmake/mimalloc-config-version.cmake") include("cmake/mimalloc-config-version.cmake")
@ -181,10 +184,23 @@ string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LC)
if(NOT(CMAKE_BUILD_TYPE_LC MATCHES "^(release|relwithdebinfo|minsizerel)$")) 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 set(mi_basename "${mi_basename}-${CMAKE_BUILD_TYPE_LC}") #append build type (e.g. -debug) if not a release version
endif() 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 "")
message(STATUS "Library base name: ${mi_basename}") message(STATUS "Library base name: ${mi_basename}")
message(STATUS "Build type : ${CMAKE_BUILD_TYPE_LC}") message(STATUS "Build type : ${CMAKE_BUILD_TYPE_LC}")
message(STATUS "Install directory: ${mi_install_dir}") message(STATUS "Install directory: ${mi_install_dir}")
message(STATUS "Build targets : ${mi_build_targets}")
message(STATUS "") message(STATUS "")
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -192,6 +208,7 @@ message(STATUS "")
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# shared library # shared library
if(MI_BUILD_SHARED)
add_library(mimalloc SHARED ${mi_sources}) add_library(mimalloc SHARED ${mi_sources})
set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} OUTPUT_NAME ${mi_basename} ) 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_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT)
@ -209,7 +226,12 @@ if(WIN32)
COMMENT "Copy mimalloc-redirect.dll to output directory") COMMENT "Copy mimalloc-redirect.dll to output directory")
endif() endif()
install(TARGETS mimalloc EXPORT mimalloc DESTINATION ${mi_install_dir} LIBRARY)
install(EXPORT mimalloc DESTINATION ${mi_install_dir}/cmake)
endif()
# static library # static library
if (MI_BUILD_STATIC)
add_library(mimalloc-static STATIC ${mi_sources}) add_library(mimalloc-static STATIC ${mi_sources})
set_property(TARGET mimalloc-static PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET mimalloc-static PROPERTY POSITION_INDEPENDENT_CODE ON)
target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB) target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB)
@ -228,17 +250,17 @@ else()
set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename}) set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename})
endif() 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(TARGETS mimalloc-static EXPORT mimalloc DESTINATION ${mi_install_dir})
endif()
# install include files
install(FILES include/mimalloc.h DESTINATION ${mi_install_dir}/include) 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-override.h DESTINATION ${mi_install_dir}/include)
install(FILES include/mimalloc-new-delete.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.cmake DESTINATION ${mi_install_dir}/cmake)
install(FILES cmake/mimalloc-config-version.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 # 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_symlink "${CMAKE_SHARED_MODULE_PREFIX}${mi_basename}${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(mi_soname "mimalloc-${mi_version}/${mi_symlink}.${mi_version}") set(mi_soname "mimalloc-${mi_version}/${mi_symlink}.${mi_version}")
@ -247,6 +269,7 @@ if(NOT WIN32)
endif() endif()
# single object file for more predictable static overriding # single object file for more predictable static overriding
if (MI_BUILD_OBJECT)
add_library(mimalloc-obj OBJECT src/static.c) add_library(mimalloc-obj OBJECT src/static.c)
set_property(TARGET mimalloc-obj PROPERTY POSITION_INDEPENDENT_CODE ON) set_property(TARGET mimalloc-obj PROPERTY POSITION_INDEPENDENT_CODE ON)
target_compile_definitions(mimalloc-obj PRIVATE ${mi_defines}) target_compile_definitions(mimalloc-obj PRIVATE ${mi_defines})
@ -264,6 +287,7 @@ target_include_directories(mimalloc-obj PUBLIC
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/mimalloc-obj.dir/src/static.c${CMAKE_C_OUTPUT_EXTENSION} 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} ) RENAME ${mi_basename}${CMAKE_C_OUTPUT_EXTENSION} )
endif()
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# API surface testing # API surface testing
@ -291,10 +315,16 @@ endif()
# Set override properties # Set override properties
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if (MI_OVERRIDE MATCHES "ON") if (MI_OVERRIDE MATCHES "ON")
if (MI_BUILD_SHARED)
target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE)
endif()
if(NOT WIN32) if(NOT WIN32)
# It is only possible to override malloc on Windows when building as a DLL. # It is only possible to override malloc on Windows when building as a DLL.
if (MI_BUILD_STATIC)
target_compile_definitions(mimalloc-static PRIVATE MI_MALLOC_OVERRIDE) target_compile_definitions(mimalloc-static PRIVATE MI_MALLOC_OVERRIDE)
endif()
if (MI_BUILD_OBJECT)
target_compile_definitions(mimalloc-obj PRIVATE MI_MALLOC_OVERRIDE) target_compile_definitions(mimalloc-obj PRIVATE MI_MALLOC_OVERRIDE)
endif() endif()
endif() endif()
endif()

View file

@ -8,7 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file
#ifndef MIMALLOC_H #ifndef MIMALLOC_H
#define 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 // Compiler specific attributes

View file

@ -11,7 +11,7 @@ mimalloc (pronounced "me-malloc")
is a general purpose allocator with excellent [performance](#performance) characteristics. is a general purpose allocator with excellent [performance](#performance) characteristics.
Initially developed by Daan Leijen for the run-time systems of the 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. [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 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: 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 ### 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, * 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, stability fix for Windows 7, fix multiple mimalloc instances in one executable, fix `strnlen` overload,
fix aligned debug padding. fix aligned debug padding.

View file

@ -242,7 +242,6 @@ static bool _mi_heap_done(mi_heap_t* heap) {
heap = heap->tld->heap_backing; heap = heap->tld->heap_backing;
if (!mi_heap_is_initialized(heap)) return false; if (!mi_heap_is_initialized(heap)) return false;
// delete all non-backing heaps in this thread // delete all non-backing heaps in this thread
mi_heap_t* curr = heap->tld->heaps; mi_heap_t* curr = heap->tld->heaps;
while (curr != NULL) { while (curr != NULL) {
@ -261,12 +260,13 @@ static bool _mi_heap_done(mi_heap_t* heap) {
_mi_heap_collect_abandon(heap); _mi_heap_collect_abandon(heap);
} }
// merge stats // merge stats
_mi_stats_done(&heap->tld->stats); _mi_stats_done(&heap->tld->stats);
// free if not the main thread // free if not the main thread
if (heap != &_mi_heap_main) { 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); _mi_os_free(heap, sizeof(mi_thread_data_t), &_mi_stats_main);
} }
#if 0 #if 0
@ -381,10 +381,14 @@ void mi_thread_done(void) mi_attr_noexcept {
} }
static void _mi_thread_done(mi_heap_t* heap) { 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 // stats
if (!_mi_is_main_thread() && mi_heap_is_initialized(heap)) { if (!_mi_is_main_thread() && mi_heap_is_initialized(heap)) {
_mi_stat_decrease(&heap->tld->stats.threads, 1); _mi_stat_decrease(&heap->tld->stats.threads, 1);
} }
// abandon the thread local heap // 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
} }

View file

@ -810,6 +810,27 @@ static mi_page_t* mi_large_huge_page_alloc(mi_heap_t* heap, size_t size) {
} }
// 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_MEDIUM_OBJ_SIZE_MAX - MI_PADDING_SIZE) )) {
if (mi_unlikely(req_size > PTRDIFF_MAX)) { // we don't allocate more than PTRDIFF_MAX (see <https://sourceware.org/ml/libc-announce/2019/msg00001.html>)
_mi_error_message(EOVERFLOW, "allocation request is too large (%zu b requested)\n", req_size);
return NULL;
}
else {
return mi_large_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);
return mi_find_free_page(heap, size);
}
}
// Generic allocation routine if the fast path (`alloc.c:mi_page_malloc`) does not succeed. // 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. // 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 void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept
@ -829,23 +850,13 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept
// free delayed frees from other threads // free delayed frees from other threads
_mi_heap_delayed_free(heap); _mi_heap_delayed_free(heap);
// huge allocation? // find (or allocate) a page of the right size
mi_page_t* page; mi_page_t* page = mi_find_page(heap, size);
const size_t req_size = size - MI_PADDING_SIZE; // correct for padding_size in case of an overflow on `size` if (mi_unlikely(page == NULL)) { // first time out of memory, try to collect and retry the allocation once more
if (mi_unlikely(req_size > (MI_MEDIUM_OBJ_SIZE_MAX - MI_PADDING_SIZE))) { mi_heap_collect(heap, true /* force */);
if (mi_unlikely(req_size > PTRDIFF_MAX)) { // we don't allocate more than PTRDIFF_MAX (see <https://sourceware.org/ml/libc-announce/2019/msg00001.html>) page = mi_find_page(heap, size);
_mi_error_message(EOVERFLOW, "allocation request is too large (%zu b requested)\n", req_size);
return NULL;
}
else {
page = mi_large_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);
} }
if (mi_unlikely(page == NULL)) { // out of memory if (mi_unlikely(page == NULL)) { // out of memory
_mi_error_message(ENOMEM, "cannot allocate memory (%zu bytes requested)\n", size); _mi_error_message(ENOMEM, "cannot allocate memory (%zu bytes requested)\n", size);
return NULL; return NULL;

View file

@ -7,11 +7,15 @@
#include <mimalloc.h> #include <mimalloc.h>
#include <new> #include <new>
#include <vector> #include <vector>
#include <future>
#include <iostream>
#include <thread> #include <thread>
#include <mimalloc.h> #include <mimalloc.h>
#include <assert.h> #include <assert.h>
#include <mimalloc-new-delete.h>
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
static void msleep(unsigned long msecs) { Sleep(msecs); } static void msleep(unsigned long msecs) { Sleep(msecs); }
@ -25,6 +29,7 @@ void heap_no_delete(); // issue #202
void heap_late_free(); // issue #204 void heap_late_free(); // issue #204
void padding_shrink(); // issue #209 void padding_shrink(); // issue #209
void various_tests(); void various_tests();
void test_mt_shutdown();
int main() { int main() {
mi_stats_reset(); // ignore earlier allocations mi_stats_reset(); // ignore earlier allocations
@ -33,6 +38,7 @@ int main() {
heap_late_free(); heap_late_free();
padding_shrink(); padding_shrink();
various_tests(); various_tests();
//test_mt_shutdown();
mi_stats_print(NULL); mi_stats_print(NULL);
return 0; return 0;
} }
@ -173,3 +179,29 @@ void heap_thread_free_large() {
t1.join(); 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;
}