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,53 +208,59 @@ message(STATUS "")
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# shared library # shared library
add_library(mimalloc SHARED ${mi_sources}) if(MI_BUILD_SHARED)
set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} OUTPUT_NAME ${mi_basename} ) add_library(mimalloc SHARED ${mi_sources})
target_compile_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT) set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} OUTPUT_NAME ${mi_basename} )
target_compile_options(mimalloc PRIVATE ${mi_cflags}) target_compile_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT)
target_link_libraries(mimalloc PUBLIC ${mi_libraries}) target_compile_options(mimalloc PRIVATE ${mi_cflags})
target_include_directories(mimalloc PUBLIC target_link_libraries(mimalloc PUBLIC ${mi_libraries})
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> target_include_directories(mimalloc PUBLIC
$<INSTALL_INTERFACE:${mi_install_dir}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
) $<INSTALL_INTERFACE:${mi_install_dir}/include>
if(WIN32) )
# On windows copy the mimalloc redirection dll too. if(WIN32)
target_link_libraries(mimalloc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect.lib) # On windows copy the mimalloc redirection dll too.
add_custom_command(TARGET mimalloc POST_BUILD target_link_libraries(mimalloc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect.lib)
COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect.dll" $<TARGET_FILE_DIR:mimalloc> add_custom_command(TARGET mimalloc POST_BUILD
COMMENT "Copy mimalloc-redirect.dll to output directory") COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect.dll" $<TARGET_FILE_DIR:mimalloc>
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() endif()
# static library # static library
add_library(mimalloc-static STATIC ${mi_sources}) if (MI_BUILD_STATIC)
set_property(TARGET mimalloc-static PROPERTY POSITION_INDEPENDENT_CODE ON) add_library(mimalloc-static STATIC ${mi_sources})
target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB) set_property(TARGET mimalloc-static PROPERTY POSITION_INDEPENDENT_CODE ON)
target_compile_options(mimalloc-static PRIVATE ${mi_cflags}) target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB)
target_link_libraries(mimalloc-static PUBLIC ${mi_libraries}) target_compile_options(mimalloc-static PRIVATE ${mi_cflags})
target_include_directories(mimalloc-static PUBLIC target_link_libraries(mimalloc-static PUBLIC ${mi_libraries})
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> target_include_directories(mimalloc-static PUBLIC
$<INSTALL_INTERFACE:${mi_install_dir}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
) $<INSTALL_INTERFACE:${mi_install_dir}/include>
if(WIN32) )
# When building both static and shared libraries on Windows, a static library should use a if(WIN32)
# different output name to avoid the conflict with the import library of a shared one. # When building both static and shared libraries on Windows, a static library should use a
string(REPLACE "mimalloc" "mimalloc-static" mi_output_name ${mi_basename}) # different output name to avoid the conflict with the import library of a shared one.
set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_output_name}) string(REPLACE "mimalloc" "mimalloc-static" mi_output_name ${mi_basename})
else() set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_output_name})
set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename}) else()
set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename})
endif()
install(TARGETS mimalloc-static EXPORT mimalloc DESTINATION ${mi_install_dir})
endif() endif()
# install static and shared library, and the include files # install include files
install(TARGETS mimalloc EXPORT mimalloc DESTINATION ${mi_install_dir} LIBRARY)
install(TARGETS mimalloc-static EXPORT mimalloc DESTINATION ${mi_install_dir})
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,23 +269,25 @@ if(NOT WIN32)
endif() endif()
# single object file for more predictable static overriding # single object file for more predictable static overriding
add_library(mimalloc-obj OBJECT src/static.c) if (MI_BUILD_OBJECT)
set_property(TARGET mimalloc-obj PROPERTY POSITION_INDEPENDENT_CODE ON) add_library(mimalloc-obj OBJECT src/static.c)
target_compile_definitions(mimalloc-obj PRIVATE ${mi_defines}) set_property(TARGET mimalloc-obj PROPERTY POSITION_INDEPENDENT_CODE ON)
target_compile_options(mimalloc-obj PRIVATE ${mi_cflags}) target_compile_definitions(mimalloc-obj PRIVATE ${mi_defines})
target_include_directories(mimalloc-obj PUBLIC target_compile_options(mimalloc-obj PRIVATE ${mi_cflags})
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> target_include_directories(mimalloc-obj PUBLIC
$<INSTALL_INTERFACE:${mi_install_dir}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
) $<INSTALL_INTERFACE:${mi_install_dir}/include>
)
# the following seems to lead to cmake warnings/errors on some systems, disable for now :-( # 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}) # install(TARGETS mimalloc-obj EXPORT mimalloc DESTINATION ${mi_install_dir})
# the FILES expression can also be: $<TARGET_OBJECTS:mimalloc-obj> # the FILES expression can also be: $<TARGET_OBJECTS:mimalloc-obj>
# but that fails cmake versions less than 3.10 so we leave it as is for now # 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} 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")
target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) if (MI_BUILD_SHARED)
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.
target_compile_definitions(mimalloc-static PRIVATE MI_MALLOC_OVERRIDE) if (MI_BUILD_STATIC)
target_compile_definitions(mimalloc-obj 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)
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.
@ -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 - 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), exploit cannot reach into the metadata),
- All free list pointers are - All free list pointers are
[encoded](https://github.com/microsoft/mimalloc/blob/783e3377f79ee82af43a0793910a9f2d01ac7863/include/mimalloc-internal.h#L396) [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, 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), - 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 - 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 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. 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. As always, evaluate with care as part of an overall security strategy as all of the above are mitigations but not guarantees.
## Debug Mode ## 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. - 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. - All objects have padding at the end to detect (byte precise) heap block overflows.

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) {
@ -260,13 +259,14 @@ static bool _mi_heap_done(mi_heap_t* heap) {
if (heap != &_mi_heap_main) { if (heap != &_mi_heap_main) {
_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,12 +381,16 @@ 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
} }
void _mi_heap_set_default_direct(mi_heap_t* heap) { void _mi_heap_set_default_direct(mi_heap_t* heap) {

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,14 +29,16 @@ 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
heap_thread_free_large(); heap_thread_free_large();
heap_no_delete(); heap_no_delete();
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;
} }
@ -53,20 +59,20 @@ public:
}; };
void various_tests() { void various_tests() {
atexit(free_p); atexit(free_p);
void* p1 = malloc(78); void* p1 = malloc(78);
void* p2 = mi_malloc_aligned(16,24); void* p2 = mi_malloc_aligned(16, 24);
free(p1); free(p1);
p1 = malloc(8); p1 = malloc(8);
char* s = mi_strdup("hello\n"); char* s = mi_strdup("hello\n");
//char* s = _strdup("hello\n"); //char* s = _strdup("hello\n");
//char* buf = NULL; //char* buf = NULL;
//size_t len; //size_t len;
//_dupenv_s(&buf,&len,"MIMALLOC_VERBOSE"); //_dupenv_s(&buf,&len,"MIMALLOC_VERBOSE");
//mi_free(buf); //mi_free(buf);
mi_free(p2); mi_free(p2);
p2 = malloc(16); p2 = malloc(16);
p1 = realloc(p1, 32); p1 = realloc(p1, 32);
@ -76,7 +82,7 @@ void various_tests() {
Test* t = new Test(42); Test* t = new Test(42);
delete t; delete t;
t = new (std::nothrow) Test(42); t = new (std::nothrow) Test(42);
delete t; delete t;
} }
class Static { class Static {
@ -105,7 +111,7 @@ bool test_stl_allocator1() {
struct some_struct { int i; int j; double z; }; struct some_struct { int i; int j; double z; };
bool test_stl_allocator2() { bool test_stl_allocator2() {
std::vector<some_struct, mi_stl_allocator<some_struct> > vec; std::vector<some_struct, mi_stl_allocator<some_struct> > vec;
vec.push_back(some_struct()); vec.push_back(some_struct());
vec.pop_back(); vec.pop_back();
@ -117,13 +123,13 @@ bool test_stl_allocator2() {
// Issue #202 // Issue #202
void heap_no_delete_worker() { void heap_no_delete_worker() {
mi_heap_t* heap = mi_heap_new(); 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 // mi_heap_delete(heap); // uncomment to prevent assertion
} }
void heap_no_delete() { void heap_no_delete() {
auto t1 = std::thread(heap_no_delete_worker); auto t1 = std::thread(heap_no_delete_worker);
t1.join(); t1.join();
} }
@ -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;
}