merge from dev
This commit is contained in:
commit
6568059cc6
@ -7,8 +7,7 @@ set(CMAKE_CXX_STANDARD 17)
|
|||||||
option(MI_OVERRIDE "Override the standard malloc interface" ON)
|
option(MI_OVERRIDE "Override the standard malloc interface" ON)
|
||||||
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_DEBUG_FULL "Use full internal heap invariant checking in DEBUG mode" OFF)
|
option(MI_DEBUG_FULL "Use full internal heap invariant checking in DEBUG mode" OFF)
|
||||||
option(MI_SECURE "Use security mitigations (like guard pages, allocation randomization, 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_SECURE_FULL "Use full security mitigations, may be more expensive (includes double-free mitigation)" OFF)
|
|
||||||
option(MI_USE_CXX "Use the C++ compiler to compile the library" OFF)
|
option(MI_USE_CXX "Use the C++ compiler to compile the library" OFF)
|
||||||
option(MI_SEE_ASM "Generate assembly files" 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_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanism (Unix)" OFF)
|
||||||
@ -73,15 +72,9 @@ if(MI_OVERRIDE MATCHES "ON")
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MI_SECURE_FULL MATCHES "ON")
|
if(MI_SECURE MATCHES "ON")
|
||||||
message(STATUS "Set full secure build (may be more expensive) (MI_SECURE_FULL=ON)")
|
message(STATUS "Set full secure build (MI_SECURE=ON)")
|
||||||
list(APPEND mi_defines MI_SECURE=4)
|
list(APPEND mi_defines MI_SECURE=4)
|
||||||
set(MI_SECURE "ON")
|
|
||||||
else()
|
|
||||||
if(MI_SECURE MATCHES "ON")
|
|
||||||
message(STATUS "Set secure build (MI_SECURE=ON)")
|
|
||||||
list(APPEND mi_defines MI_SECURE=3)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MI_SEE_ASM MATCHES "ON")
|
if(MI_SEE_ASM MATCHES "ON")
|
||||||
@ -95,7 +88,7 @@ if(MI_CHECK_FULL MATCHES "ON")
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MI_DEBUG_FULL MATCHES "ON")
|
if(MI_DEBUG_FULL MATCHES "ON")
|
||||||
message(STATUS "Set debug level to full invariant checking (MI_DEBUG_FULL=ON)")
|
message(STATUS "Set debug level to full internal invariant checking (MI_DEBUG_FULL=ON)")
|
||||||
list(APPEND mi_defines MI_DEBUG=3) # full invariant checking
|
list(APPEND mi_defines MI_DEBUG=3) # full invariant checking
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -35,22 +35,32 @@ jobs:
|
|||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
BuildType: debug
|
BuildType: debug
|
||||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_CHECK_FULL=ON
|
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON
|
||||||
Release:
|
Release:
|
||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
BuildType: release
|
BuildType: release
|
||||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release
|
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release
|
||||||
|
Secure:
|
||||||
|
CC: gcc
|
||||||
|
CXX: g++
|
||||||
|
BuildType: secure
|
||||||
|
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON
|
||||||
Debug Clang:
|
Debug Clang:
|
||||||
CC: clang
|
CC: clang
|
||||||
CXX: clang++
|
CXX: clang++
|
||||||
BuildType: debug-clang
|
BuildType: debug-clang
|
||||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_CHECK_FULL=ON
|
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON
|
||||||
Release Clang:
|
Release Clang:
|
||||||
CC: clang
|
CC: clang
|
||||||
CXX: clang++
|
CXX: clang++
|
||||||
BuildType: release-clang
|
BuildType: release-clang
|
||||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release
|
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release
|
||||||
|
Secure Clang:
|
||||||
|
CC: clang
|
||||||
|
CXX: clang++
|
||||||
|
BuildType: secure-clang
|
||||||
|
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- task: CMake@1
|
- task: CMake@1
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
|||||||
set(mi_version_major 1)
|
set(mi_version_major 1)
|
||||||
set(mi_version_minor 1)
|
set(mi_version_minor 2)
|
||||||
set(mi_version ${mi_version_major}.${mi_version_minor})
|
set(mi_version ${mi_version_major}.${mi_version_minor})
|
||||||
|
|
||||||
set(PACKAGE_VERSION ${mi_version})
|
set(PACKAGE_VERSION ${mi_version})
|
||||||
|
72
ide/vs2019/mimalloc-override.vcxproj.filters
Normal file
72
ide/vs2019/mimalloc-override.vcxproj.filters
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\src\options.c">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\alloc.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\alloc-aligned.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\alloc-override.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\alloc-posix.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\heap.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\init.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\memory.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\os.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\page.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\page-queue.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\segment.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\stats.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\mimalloc-atomic.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-internal.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\mimalloc-new-delete.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\mimalloc-override.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\mimalloc-types.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{f1fccf27-17b9-42dd-ba51-6070baff85c6}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{39cb7e38-69d0-43fb-8406-6a0f7cefc3b4}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
75
ide/vs2019/mimalloc.vcxproj.filters
Normal file
75
ide/vs2019/mimalloc.vcxproj.filters
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\src\alloc.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\alloc-aligned.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\alloc-override.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\alloc-override-osx.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\alloc-posix.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\heap.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\init.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\memory.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\options.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\os.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\page.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\page-queue.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\segment.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\stats.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-atomic.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-internal.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\mimalloc-new-delete.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-override.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-types.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{2b556b10-f559-4b2d-896e-142652adbf0c}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{852a14ae-6dde-4e95-8077-ca705e97e5af}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -284,14 +284,20 @@ static inline mi_segment_t* _mi_page_segment(const mi_page_t* page) {
|
|||||||
return segment;
|
return segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the page containing the pointer
|
// used internally
|
||||||
static inline mi_page_t* _mi_segment_page_of(const mi_segment_t* segment, const void* p) {
|
static inline uintptr_t _mi_segment_page_idx_of(const mi_segment_t* segment, const void* p) {
|
||||||
// if (segment->page_size > MI_SEGMENT_SIZE) return &segment->pages[0]; // huge pages
|
// if (segment->page_size > MI_SEGMENT_SIZE) return &segment->pages[0]; // huge pages
|
||||||
ptrdiff_t diff = (uint8_t*)p - (uint8_t*)segment;
|
ptrdiff_t diff = (uint8_t*)p - (uint8_t*)segment;
|
||||||
mi_assert_internal(diff >= 0 && (size_t)diff < MI_SEGMENT_SIZE);
|
mi_assert_internal(diff >= 0 && (size_t)diff < MI_SEGMENT_SIZE);
|
||||||
uintptr_t idx = (uintptr_t)diff >> segment->page_shift;
|
uintptr_t idx = (uintptr_t)diff >> segment->page_shift;
|
||||||
mi_assert_internal(idx < segment->capacity);
|
mi_assert_internal(idx < segment->capacity);
|
||||||
mi_assert_internal(segment->page_kind <= MI_PAGE_MEDIUM || idx == 0);
|
mi_assert_internal(segment->page_kind <= MI_PAGE_MEDIUM || idx == 0);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the page containing the pointer
|
||||||
|
static inline mi_page_t* _mi_segment_page_of(const mi_segment_t* segment, const void* p) {
|
||||||
|
uintptr_t idx = _mi_segment_page_idx_of(segment, p);
|
||||||
return &((mi_segment_t*)segment)->pages[idx];
|
return &((mi_segment_t*)segment)->pages[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,53 +390,67 @@ static inline void mi_page_set_has_aligned(mi_page_t* page, bool has_aligned) {
|
|||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Encoding/Decoding the free list next pointers
|
// Encoding/Decoding the free list next pointers
|
||||||
|
// Note: we pass a `null` value to be used as the `NULL` value for the
|
||||||
|
// end of a free list. This is to prevent the cookie itself to ever
|
||||||
|
// be present among user blocks (as `cookie^0==cookie`).
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
static inline bool mi_is_in_same_segment(const void* p, const void* q) {
|
static inline bool mi_is_in_same_segment(const void* p, const void* q) {
|
||||||
return (_mi_ptr_segment(p) == _mi_ptr_segment(q));
|
return (_mi_ptr_segment(p) == _mi_ptr_segment(q));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline mi_block_t* mi_block_nextx( uintptr_t cookie, const mi_block_t* block ) {
|
static inline bool mi_is_in_same_page(const void* p, const void* q) {
|
||||||
|
mi_segment_t* segmentp = _mi_ptr_segment(p);
|
||||||
|
mi_segment_t* segmentq = _mi_ptr_segment(q);
|
||||||
|
if (segmentp != segmentq) return false;
|
||||||
|
uintptr_t idxp = _mi_segment_page_idx_of(segmentp, p);
|
||||||
|
uintptr_t idxq = _mi_segment_page_idx_of(segmentq, q);
|
||||||
|
return (idxp == idxq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline mi_block_t* mi_block_nextx( const void* null, const mi_block_t* block, uintptr_t cookie ) {
|
||||||
#ifdef MI_ENCODE_FREELIST
|
#ifdef MI_ENCODE_FREELIST
|
||||||
return (mi_block_t*)(block->next ^ cookie);
|
mi_block_t* b = (mi_block_t*)(block->next ^ cookie);
|
||||||
|
if (mi_unlikely((void*)b==null)) { b = NULL; }
|
||||||
|
return b;
|
||||||
#else
|
#else
|
||||||
UNUSED(cookie);
|
UNUSED(cookie); UNUSED(null);
|
||||||
return (mi_block_t*)block->next;
|
return (mi_block_t*)block->next;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mi_block_set_nextx(uintptr_t cookie, mi_block_t* block, const mi_block_t* next) {
|
static inline void mi_block_set_nextx(const void* null, mi_block_t* block, const mi_block_t* next, uintptr_t cookie) {
|
||||||
#ifdef MI_ENCODE_FREELIST
|
#ifdef MI_ENCODE_FREELIST
|
||||||
|
if (mi_unlikely(next==NULL)) { next = (mi_block_t*)null; }
|
||||||
block->next = (mi_encoded_t)next ^ cookie;
|
block->next = (mi_encoded_t)next ^ cookie;
|
||||||
#else
|
#else
|
||||||
UNUSED(cookie);
|
UNUSED(cookie); UNUSED(null);
|
||||||
block->next = (mi_encoded_t)next;
|
block->next = (mi_encoded_t)next;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline mi_block_t* mi_block_next(const mi_page_t* page, const mi_block_t* block) {
|
static inline mi_block_t* mi_block_next(const mi_page_t* page, const mi_block_t* block) {
|
||||||
#ifdef MI_ENCODE_FREELIST
|
#ifdef MI_ENCODE_FREELIST
|
||||||
mi_block_t* next = mi_block_nextx(page->cookie,block);
|
mi_block_t* next = mi_block_nextx(page,block,page->cookie);
|
||||||
// check for free list corruption: is `next` at least in our segment range?
|
// check for free list corruption: is `next` at least in our segment range?
|
||||||
// TODO: it is better to check if it is actually inside our page but that is more expensive
|
// TODO: check if `next` is `page->block_size` aligned?
|
||||||
// to calculate. Perhaps with a relative free list this becomes feasible?
|
if (next!=NULL && !mi_is_in_same_page(block, next)) {
|
||||||
if (next!=NULL && !mi_is_in_same_segment(block, next)) {
|
|
||||||
_mi_fatal_error("corrupted free list entry of size %zub at %p: value 0x%zx\n", page->block_size, block, (uintptr_t)next);
|
_mi_fatal_error("corrupted free list entry of size %zub at %p: value 0x%zx\n", page->block_size, block, (uintptr_t)next);
|
||||||
next = NULL;
|
next = NULL;
|
||||||
}
|
}
|
||||||
return next;
|
return next;
|
||||||
#else
|
#else
|
||||||
UNUSED(page);
|
UNUSED(page);
|
||||||
return mi_block_nextx(0, block);
|
return mi_block_nextx(page,block,0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mi_block_set_next(const mi_page_t* page, mi_block_t* block, const mi_block_t* next) {
|
static inline void mi_block_set_next(const mi_page_t* page, mi_block_t* block, const mi_block_t* next) {
|
||||||
#ifdef MI_ENCODE_FREELIST
|
#ifdef MI_ENCODE_FREELIST
|
||||||
mi_block_set_nextx(page->cookie,block,next);
|
mi_block_set_nextx(page,block,next, page->cookie);
|
||||||
#else
|
#else
|
||||||
UNUSED(page);
|
UNUSED(page);
|
||||||
mi_block_set_nextx(0, block, next);
|
mi_block_set_nextx(page,block, next,0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,16 +26,16 @@ terms of the MIT license. A copy of the license can be found in the file
|
|||||||
// #define MI_SECURE 1 // guard page around metadata
|
// #define MI_SECURE 1 // guard page around metadata
|
||||||
// #define MI_SECURE 2 // guard page around each mimalloc page
|
// #define MI_SECURE 2 // guard page around each mimalloc page
|
||||||
// #define MI_SECURE 3 // encode free lists (detect corrupted free list (buffer overflow), and invalid pointer free)
|
// #define MI_SECURE 3 // encode free lists (detect corrupted free list (buffer overflow), and invalid pointer free)
|
||||||
// #define MI_SECURE 4 // experimental, may be more expensive: checks for double free. (cmake -DMI_SECURE_FULL=ON)
|
// #define MI_SECURE 4 // checks for double free. (may be more expensive)
|
||||||
|
|
||||||
#if !defined(MI_SECURE)
|
#if !defined(MI_SECURE)
|
||||||
#define MI_SECURE 0
|
#define MI_SECURE 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Define MI_DEBUG for debug mode
|
// Define MI_DEBUG for debug mode
|
||||||
// #define MI_DEBUG 1 // basic assertion checks and statistics, check double free, corrupted free list, and invalid pointer free.
|
// #define MI_DEBUG 1 // basic assertion checks and statistics, check double free, corrupted free list, and invalid pointer free.
|
||||||
// #define MI_DEBUG 2 // + internal assertion checks
|
// #define MI_DEBUG 2 // + internal assertion checks
|
||||||
// #define MI_DEBUG 3 // + extensive internal invariant checking (cmake -DMI_CHECK_FULL=ON)
|
// #define MI_DEBUG 3 // + extensive internal invariant checking (cmake -DMI_DEBUG_FULL=ON)
|
||||||
#if !defined(MI_DEBUG)
|
#if !defined(MI_DEBUG)
|
||||||
#if !defined(NDEBUG) || defined(_DEBUG)
|
#if !defined(NDEBUG) || defined(_DEBUG)
|
||||||
#define MI_DEBUG 2
|
#define MI_DEBUG 2
|
||||||
|
@ -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 110 // major + 2 digits minor
|
#define MI_MALLOC_VERSION 120 // major + 2 digits minor
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Compiler specific attributes
|
// Compiler specific attributes
|
||||||
|
34
readme.md
34
readme.md
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
<img align="left" width="100" height="100" src="doc/mimalloc-logo.png"/>
|
<img align="left" width="100" height="100" src="doc/mimalloc-logo.png"/>
|
||||||
|
|
||||||
[<img align="right" src="https://dev.azure.com/Daan0324/mimalloc/_apis/build/status/microsoft.mimalloc?branchName=master"/>](https://dev.azure.com/Daan0324/mimalloc/_build?definitionId=1&_a=summary)
|
[<img align="right" src="https://dev.azure.com/Daan0324/mimalloc/_apis/build/status/microsoft.mimalloc?branchName=dev"/>](https://dev.azure.com/Daan0324/mimalloc/_build?definitionId=1&_a=summary)
|
||||||
|
|
||||||
# mimalloc
|
# mimalloc
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ Notable aspects of the design include:
|
|||||||
programs.
|
programs.
|
||||||
- __secure__: _mimalloc_ can be built in secure mode, adding guard pages,
|
- __secure__: _mimalloc_ can be built in secure mode, adding guard pages,
|
||||||
randomized allocation, encrypted free lists, etc. to protect against various
|
randomized allocation, encrypted free lists, etc. to protect against various
|
||||||
heap vulnerabilities. The performance penalty is only around 3% on average
|
heap vulnerabilities. The performance penalty is usually around 10% on average
|
||||||
over our benchmarks.
|
over our benchmarks.
|
||||||
- __first-class heaps__: efficiently create and use multiple heaps to allocate across different regions.
|
- __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.
|
A heap can be destroyed at once instead of deallocating each object separately.
|
||||||
@ -56,6 +56,7 @@ Enjoy!
|
|||||||
|
|
||||||
### Releases
|
### Releases
|
||||||
|
|
||||||
|
* 2019-11-22, `v1.2.0`: stable release 1.2: bug fixes, improved secure mode (free list corruption checks, double free mitigation). Improved dynamic overriding on Windows.
|
||||||
* 2019-10-07, `v1.1.0`: stable release 1.1.
|
* 2019-10-07, `v1.1.0`: stable release 1.1.
|
||||||
* 2019-09-01, `v1.0.8`: pre-release 8: more robust windows dynamic overriding, initial huge page support.
|
* 2019-09-01, `v1.0.8`: pre-release 8: more robust windows dynamic overriding, initial huge page support.
|
||||||
* 2019-08-10, `v1.0.6`: pre-release 6: various performance improvements.
|
* 2019-08-10, `v1.0.6`: pre-release 6: various performance improvements.
|
||||||
@ -64,7 +65,7 @@ Enjoy!
|
|||||||
|
|
||||||
## Windows
|
## Windows
|
||||||
|
|
||||||
Open `ide/vs2017/mimalloc.sln` in Visual Studio 2017 and build.
|
Open `ide/vs2019/mimalloc.sln` in Visual Studio 2019 and build (or `ide/vs2017/mimalloc.sln`).
|
||||||
The `mimalloc` project builds a static library (in `out/msvc-x64`), while the
|
The `mimalloc` project builds a static library (in `out/msvc-x64`), while the
|
||||||
`mimalloc-override` project builds a DLL for overriding malloc
|
`mimalloc-override` project builds a DLL for overriding malloc
|
||||||
in the entire program.
|
in the entire program.
|
||||||
@ -97,7 +98,7 @@ maintains detailed statistics as:
|
|||||||
This will name the shared library as `libmimalloc-debug.so`.
|
This will name the shared library as `libmimalloc-debug.so`.
|
||||||
|
|
||||||
Finally, you can build a _secure_ version that uses guard pages, encrypted
|
Finally, you can build a _secure_ version that uses guard pages, encrypted
|
||||||
free lists, etc, as:
|
free lists, etc., as:
|
||||||
```
|
```
|
||||||
> mkdir -p out/secure
|
> mkdir -p out/secure
|
||||||
> cd out/secure
|
> cd out/secure
|
||||||
@ -138,6 +139,9 @@ target_link_libraries(myapp PUBLIC mimalloc-static)
|
|||||||
```
|
```
|
||||||
to link with the static library. See `test\CMakeLists.txt` for an example.
|
to link with the static library. See `test\CMakeLists.txt` for an example.
|
||||||
|
|
||||||
|
For best performance in C++ programs, it is also recommended to override the
|
||||||
|
global `new` and `delete` operators. For convience, mimalloc provides
|
||||||
|
[mimalloc-new-delete.h](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-new-delete.h) which does this for you -- just include it in a single(!) source file in your project.
|
||||||
|
|
||||||
You can pass environment variables to print verbose messages (`MIMALLOC_VERBOSE=1`)
|
You can pass environment variables to print verbose messages (`MIMALLOC_VERBOSE=1`)
|
||||||
and statistics (`MIMALLOC_SHOW_STATS=1`) (in the debug version):
|
and statistics (`MIMALLOC_SHOW_STATS=1`) (in the debug version):
|
||||||
@ -252,20 +256,22 @@ Note: unfortunately, at this time, dynamic overriding on macOS seems broken but
|
|||||||
On Windows you need to link your program explicitly with the mimalloc
|
On Windows you need to link your program explicitly with the mimalloc
|
||||||
DLL and use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch).
|
DLL and use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch).
|
||||||
Moreover, you need to ensure the `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) is available
|
Moreover, you need to ensure the `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) is available
|
||||||
in the same folder as the mimalloc DLL at runtime (as it as referred to by the mimalloc DLL).
|
in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency).
|
||||||
The redirection DLL's ensure all calls to the C runtime malloc API get redirected to mimalloc.
|
The redirection DLL ensures that all calls to the C runtime malloc API get redirected to
|
||||||
|
mimalloc (in `mimalloc-override.dll`).
|
||||||
|
|
||||||
To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some
|
To ensure the mimalloc DLL is loaded at run-time it is easiest to insert some
|
||||||
call to the mimalloc API in the `main` function, like `mi_version()`
|
call to the mimalloc API in the `main` function, like `mi_version()`
|
||||||
(or use the `/INCLUDE:mi_version` switch on the linker). See the `mimalloc-override-test` project
|
(or use the `/INCLUDE:mi_version` switch on the linker). See the `mimalloc-override-test` project
|
||||||
for an example on how to use this.
|
for an example on how to use this. For best performance on Windows with C++, it
|
||||||
|
is highly recommended to also override the `new`/`delete` operations (as described
|
||||||
|
in the introduction).
|
||||||
|
|
||||||
The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic
|
The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic
|
||||||
overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc successfully redirected.
|
overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully redirected.
|
||||||
|
|
||||||
(Note: in principle, it should be possible to patch existing executables
|
(Note: in principle, it is possible to patch existing executables
|
||||||
that are linked with the dynamic C runtime (`ucrtbase.dll`) by just putting the mimalloc DLL into
|
that are linked with the dynamic C runtime (`ucrtbase.dll`) by just putting the `mimalloc-override.dll` into the import table (and putting `mimalloc-redirect.dll` in the same folder)
|
||||||
the import table (and putting `mimalloc-redirect.dll` in the same folder)
|
|
||||||
Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388)).
|
Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388)).
|
||||||
|
|
||||||
|
|
||||||
@ -282,6 +288,12 @@ object file. For example:
|
|||||||
> gcc -o myprogram mimalloc-override.o myfile1.c ...
|
> gcc -o myprogram mimalloc-override.o myfile1.c ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Another way to override statically that works on all platforms, is to
|
||||||
|
link statically to mimalloc (as shown in the introduction) and include a
|
||||||
|
header file in each source file that re-defines `malloc` etc. to `mi_malloc`.
|
||||||
|
This is provided by [`mimalloc-override.h`](https://github.com/microsoft/mimalloc/blob/master/include/mimalloc-override.h). This only works reliably though if all sources are
|
||||||
|
under your control or otherwise mixing of pointers from different heaps may occur!
|
||||||
|
|
||||||
|
|
||||||
# Performance
|
# Performance
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ static mi_decl_noinline bool mi_check_is_double_freex(const mi_page_t* page, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block) {
|
static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block) {
|
||||||
mi_block_t* n = mi_block_nextx(page->cookie, block); // pretend it is freed, and get the decoded first field
|
mi_block_t* n = mi_block_nextx(page, block, page->cookie); // pretend it is freed, and get the decoded first field
|
||||||
if (((uintptr_t)n & (MI_INTPTR_SIZE-1))==0 && // quick check: aligned pointer?
|
if (((uintptr_t)n & (MI_INTPTR_SIZE-1))==0 && // quick check: aligned pointer?
|
||||||
(n==NULL || mi_is_in_same_segment(block, n))) // quick check: in same segment or NULL?
|
(n==NULL || mi_is_in_same_segment(block, n))) // quick check: in same segment or NULL?
|
||||||
{
|
{
|
||||||
@ -242,7 +242,7 @@ static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* bloc
|
|||||||
mi_block_t* dfree;
|
mi_block_t* dfree;
|
||||||
do {
|
do {
|
||||||
dfree = (mi_block_t*)heap->thread_delayed_free;
|
dfree = (mi_block_t*)heap->thread_delayed_free;
|
||||||
mi_block_set_nextx(heap->cookie,block,dfree);
|
mi_block_set_nextx(heap,block,dfree, heap->cookie);
|
||||||
} while (!mi_atomic_cas_ptr_weak(mi_atomic_cast(void*,&heap->thread_delayed_free), block, dfree));
|
} while (!mi_atomic_cas_ptr_weak(mi_atomic_cast(void*,&heap->thread_delayed_free), block, dfree));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,6 +466,7 @@ void mi_process_init(void) mi_attr_noexcept {
|
|||||||
#if (MI_DEBUG)
|
#if (MI_DEBUG)
|
||||||
_mi_verbose_message("debug level : %d\n", MI_DEBUG);
|
_mi_verbose_message("debug level : %d\n", MI_DEBUG);
|
||||||
#endif
|
#endif
|
||||||
|
_mi_verbose_message("secure level: %d\n", MI_SECURE);
|
||||||
mi_thread_init();
|
mi_thread_init();
|
||||||
mi_stats_reset(); // only call stat reset *after* thread init (or the heap tld == NULL)
|
mi_stats_reset(); // only call stat reset *after* thread init (or the heap tld == NULL)
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ void _mi_heap_delayed_free(mi_heap_t* heap) {
|
|||||||
|
|
||||||
// and free them all
|
// and free them all
|
||||||
while(block != NULL) {
|
while(block != NULL) {
|
||||||
mi_block_t* next = mi_block_nextx(heap->cookie,block);
|
mi_block_t* next = mi_block_nextx(heap,block, heap->cookie);
|
||||||
// use internal free instead of regular one to keep stats etc correct
|
// use internal free instead of regular one to keep stats etc correct
|
||||||
if (!_mi_free_delayed_block(block)) {
|
if (!_mi_free_delayed_block(block)) {
|
||||||
// we might already start delayed freeing while another thread has not yet
|
// we might already start delayed freeing while another thread has not yet
|
||||||
@ -292,7 +292,7 @@ void _mi_heap_delayed_free(mi_heap_t* heap) {
|
|||||||
mi_block_t* dfree;
|
mi_block_t* dfree;
|
||||||
do {
|
do {
|
||||||
dfree = (mi_block_t*)heap->thread_delayed_free;
|
dfree = (mi_block_t*)heap->thread_delayed_free;
|
||||||
mi_block_set_nextx(heap->cookie, block, dfree);
|
mi_block_set_nextx(heap, block, dfree, heap->cookie);
|
||||||
} while (!mi_atomic_cas_ptr_weak(mi_atomic_cast(void*,&heap->thread_delayed_free), block, dfree));
|
} while (!mi_atomic_cas_ptr_weak(mi_atomic_cast(void*,&heap->thread_delayed_free), block, dfree));
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -357,7 +357,7 @@ void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq) {
|
|||||||
|
|
||||||
#if MI_DEBUG>1
|
#if MI_DEBUG>1
|
||||||
// check there are no references left..
|
// check there are no references left..
|
||||||
for (mi_block_t* block = (mi_block_t*)pheap->thread_delayed_free; block != NULL; block = mi_block_nextx(pheap->cookie, block)) {
|
for (mi_block_t* block = (mi_block_t*)pheap->thread_delayed_free; block != NULL; block = mi_block_nextx(pheap, block, pheap->cookie)) {
|
||||||
mi_assert_internal(_mi_ptr_page(block) != page);
|
mi_assert_internal(_mi_ptr_page(block) != page);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -13,7 +13,7 @@ if (NOT CMAKE_BUILD_TYPE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Import mimalloc (if installed)
|
# Import mimalloc (if installed)
|
||||||
find_package(mimalloc 1.0 REQUIRED NO_SYSTEM_ENVIRONMENT_PATH)
|
find_package(mimalloc 1.2 REQUIRED NO_SYSTEM_ENVIRONMENT_PATH)
|
||||||
message(STATUS "Found mimalloc installed at: ${MIMALLOC_TARGET_DIR}")
|
message(STATUS "Found mimalloc installed at: ${MIMALLOC_TARGET_DIR}")
|
||||||
|
|
||||||
# overriding with a dynamic library
|
# overriding with a dynamic library
|
||||||
|
@ -15,9 +15,9 @@ int main() {
|
|||||||
mi_version();
|
mi_version();
|
||||||
|
|
||||||
// detect double frees and heap corruption
|
// detect double frees and heap corruption
|
||||||
//double_free1();
|
// double_free1();
|
||||||
//double_free2();
|
// double_free2();
|
||||||
//corrupt_free();
|
// corrupt_free();
|
||||||
|
|
||||||
void* p1 = malloc(78);
|
void* p1 = malloc(78);
|
||||||
void* p2 = malloc(24);
|
void* p2 = malloc(24);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Testing allocators is difficult as bugs may only surface after particular
|
Testing allocators is difficult as bugs may only surface after particular
|
||||||
allocation patterns. The main approach to testing _mimalloc_ is therefore
|
allocation patterns. The main approach to testing _mimalloc_ is therefore
|
||||||
to have extensive internal invariant checking (see `page_is_valid` in `page.c`
|
to have extensive internal invariant checking (see `page_is_valid` in `page.c`
|
||||||
for example), which is enabled in debug mode with `-DMI_CHECK_FULL=ON`.
|
for example), which is enabled in debug mode with `-DMI_DEBUG_FULL=ON`.
|
||||||
The main testing strategy is then to run [`mimalloc-bench`][bench] using full
|
The main testing strategy is then to run [`mimalloc-bench`][bench] using full
|
||||||
invariant checking to catch any potential problems over a wide range of intensive
|
invariant checking to catch any potential problems over a wide range of intensive
|
||||||
allocation benchmarks and programs.
|
allocation benchmarks and programs.
|
||||||
|
Loading…
Reference in New Issue
Block a user