fix write to empty heap in mi_guarded build

This commit is contained in:
daanx 2024-12-08 17:23:09 -08:00
parent 68bd8744b7
commit d9a2f76ff7
3 changed files with 56 additions and 23 deletions

View file

@ -39,9 +39,10 @@ static mi_decl_restrict void* mi_heap_malloc_guarded_aligned(mi_heap_t* heap, si
static void* mi_heap_malloc_zero_no_guarded(mi_heap_t* heap, size_t size, bool zero) { static void* mi_heap_malloc_zero_no_guarded(mi_heap_t* heap, size_t size, bool zero) {
const size_t rate = heap->guarded_sample_rate; const size_t rate = heap->guarded_sample_rate;
heap->guarded_sample_rate = 0; // only write if `rate!=0` so we don't write to the constant `_mi_heap_empty`
if (rate != 0) { heap->guarded_sample_rate = 0; }
void* p = _mi_heap_malloc_zero(heap, size, zero); void* p = _mi_heap_malloc_zero(heap, size, zero);
heap->guarded_sample_rate = rate; if (rate != 0) { heap->guarded_sample_rate = rate; }
return p; return p;
} }
#else #else

View file

@ -7,6 +7,8 @@
#include <mimalloc.h> #include <mimalloc.h>
#include <mimalloc-override.h> // redefines malloc etc. #include <mimalloc-override.h> // redefines malloc etc.
static void mi_bins(void);
static void double_free1(); static void double_free1();
static void double_free2(); static void double_free2();
static void corrupt_free(); static void corrupt_free();
@ -41,6 +43,9 @@ int main() {
// test_heap_walk(); // test_heap_walk();
// alloc_huge(); // alloc_huge();
// mi_bins();
void* p1 = malloc(78); void* p1 = malloc(78);
void* p2 = malloc(24); void* p2 = malloc(24);
free(p1); free(p1);
@ -290,11 +295,11 @@ static void test_large_pages(void) {
static inline uint8_t mi_bsr32(uint32_t x); static inline uint8_t mi_bsr32(uint32_t x);
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <windows.h> //#include <Windows.h>
#include <intrin.h> #include <intrin.h>
static inline uint8_t mi_bsr32(uint32_t x) { static inline uint8_t mi_bsr32(uint32_t x) {
uint32_t idx; uint32_t idx;
_BitScanReverse((DWORD*)&idx, x); _BitScanReverse(&idx, x);
return idx; return idx;
} }
#elif defined(__GNUC__) || defined(__clang__) #elif defined(__GNUC__) || defined(__clang__)
@ -318,7 +323,7 @@ static inline uint8_t mi_bsr32(uint32_t x) {
} }
#endif #endif
/*
// Bit scan reverse: return the index of the highest bit. // Bit scan reverse: return the index of the highest bit.
uint8_t _mi_bsr(uintptr_t x) { uint8_t _mi_bsr(uintptr_t x) {
if (x == 0) return 0; if (x == 0) return 0;
@ -331,7 +336,7 @@ uint8_t _mi_bsr(uintptr_t x) {
# error "define bsr for non-32 or 64-bit platforms" # error "define bsr for non-32 or 64-bit platforms"
#endif #endif
} }
*/
static inline size_t _mi_wsize_from_size(size_t size) { static inline size_t _mi_wsize_from_size(size_t size) {
@ -408,11 +413,20 @@ static inline uint8_t _mi_bin4(size_t size) {
return bin; return bin;
} }
static size_t _mi_binx4(size_t bsize) { static size_t _mi_binx4(size_t wsize) {
if (bsize==0) return 0; size_t bin;
uint8_t b = mi_bsr32((uint32_t)bsize); if (wsize <= 1) {
if (b <= 1) return bsize; bin = 1;
size_t bin = ((b << 1) | (bsize >> (b - 1))&0x01); }
else if (wsize <= 8) {
// bin = (wsize+1)&~1; // round to double word sizes
bin = (uint8_t)wsize;
}
else {
uint8_t b = mi_bsr32((uint32_t)wsize);
if (b <= 1) return wsize;
bin = ((b << 1) | (wsize >> (b - 1))&0x01) + 3;
}
return bin; return bin;
} }
@ -424,22 +438,40 @@ static size_t _mi_binx8(size_t bsize) {
return bin; return bin;
} }
static inline size_t mi_bin(size_t wsize) {
uint8_t bin;
if (wsize <= 1) {
bin = 1;
}
else if (wsize <= 8) {
// bin = (wsize+1)&~1; // round to double word sizes
bin = (uint8_t)wsize;
}
else {
wsize--;
// find the highest bit
uint8_t b = (uint8_t)mi_bsr32((uint32_t)wsize); // note: wsize != 0
// and use the top 3 bits to determine the bin (~12.5% worst internal fragmentation).
// - adjust with 3 because we use do not round the first 8 sizes
// which each get an exact bin
bin = ((b << 2) + (uint8_t)((wsize >> (b - 2)) & 0x03)) - 3;
}
return bin;
}
static void mi_bins(void) { static void mi_bins(void) {
//printf(" QNULL(1), /* 0 */ \\\n "); //printf(" QNULL(1), /* 0 */ \\\n ");
size_t last_bin = 0; size_t last_bin = 0;
size_t min_bsize = 0; for (size_t wsize = 1; wsize <= (4*1024*1024) / 8 + 1024; wsize++) {
size_t last_bsize = 0; size_t bin = mi_bin(wsize);
for (size_t bsize = 1; bsize < 2*1024; bsize++) {
size_t size = bsize * 64 * 1024;
size_t bin = _mi_binx8(bsize);
if (bin != last_bin) { if (bin != last_bin) {
printf("min bsize: %6zd, max bsize: %6zd, bin: %6zd\n", min_bsize, last_bsize, last_bin); //printf("min bsize: %6zd, max bsize: %6zd, bin: %6zd\n", min_wsize, last_wsize, last_bin);
//printf("QNULL(%6zd), ", wsize); printf("QNULL(%6zd), ", wsize-1);
//if (last_bin%8 == 0) printf("/* %i */ \\\n ", last_bin); if (last_bin%8 == 0) printf("/* %zu */ \\\n ", last_bin);
last_bin = bin; last_bin = bin;
min_bsize = bsize;
} }
last_bsize = bsize;
} }
} }
#endif #endif

View file

@ -42,7 +42,7 @@ static int SCALE = 10;
static int ITER = 10; static int ITER = 10;
#else #else
static int THREADS = 32; // more repeatable if THREADS <= #processors static int THREADS = 32; // more repeatable if THREADS <= #processors
static int SCALE = 25; // scaling factor static int SCALE = 50; // scaling factor
static int ITER = 50; // N full iterations destructing and re-creating all threads static int ITER = 50; // N full iterations destructing and re-creating all threads
#endif #endif
@ -50,7 +50,7 @@ static int ITER = 50; // N full iterations destructing and re-creating a
#define STRESS // undefine for leak test #define STRESS // undefine for leak test
static bool allow_large_objects = true; // allow very large objects? (set to `true` if SCALE>100) static bool allow_large_objects = false; // allow very large objects? (set to `true` if SCALE>100)
static size_t use_one_size = 0; // use single object size of `N * sizeof(uintptr_t)`? static size_t use_one_size = 0; // use single object size of `N * sizeof(uintptr_t)`?
static bool main_participates = false; // main thread participates as a worker too static bool main_participates = false; // main thread participates as a worker too