merge from dev

This commit is contained in:
Daan Leijen 2021-02-24 15:53:26 -08:00
commit 4e643b6d31
2 changed files with 20 additions and 11 deletions

View File

@ -472,24 +472,33 @@ static mi_decl_cache_align _Atomic(uintptr_t) aligned_base;
// Return a 4MiB aligned address that is probably available. // Return a 4MiB aligned address that is probably available.
// If this returns NULL, the OS will determine the address but on some OS's that may not be // If this returns NULL, the OS will determine the address but on some OS's that may not be
// properly aligned which can be more costly as it needs to be adjusted afterwards. // properly aligned which can be more costly as it needs to be adjusted afterwards.
// For a size > 4GiB this always returns NULL in order to guarantee good ASLR randomization; // For a size > 1GiB this always returns NULL in order to guarantee good ASLR randomization;
// otherwise an initial large allocation of say 2TiB has a 50% chance to include (known) addresses // (otherwise an initial large allocation of say 2TiB has a 50% chance to include (known) addresses
// in the middle of the 4TiB - 8TiB address range (see issue #372). // in the middle of the 2TiB - 6TiB address range (see issue #372))
#define KK_HINT_BASE ((uintptr_t)2 << 40) // 2TiB start
#define KK_HINT_AREA ((uintptr_t)4 << 40) // upto 6TiB (since before win8 there is "only" 8TiB available to processes)
#define KK_HINT_MAX ((uintptr_t)30 << 40) // wrap after 30TiB (area after 32TiB is used for huge OS pages)
static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size)
{ {
if (try_alignment == 0 || try_alignment > MI_SEGMENT_SIZE) return NULL; if (try_alignment == 0 || try_alignment > MI_SEGMENT_SIZE) return NULL;
if ((size%MI_SEGMENT_SIZE) != 0) return NULL; if ((size%MI_SEGMENT_SIZE) != 0) return NULL;
if (size > 1*GiB) return NULL; // guarantee the chance of fixed valid address is at most 1/(4<<40 / 1<<30) = 1/4096. if (size > 1*GiB) return NULL; // guarantee the chance of fixed valid address is at most 1/(KK_HINT_AREA / 1<<30) = 1/4096.
#if (MI_SECURE>0)
size += MI_SEGMENT_SIZE; // put in `MI_SEGMENT_SIZE` virtual gaps between hinted blocks; this splits VLA's but increases guarded areas.
#endif
uintptr_t hint = mi_atomic_add_acq_rel(&aligned_base, size); uintptr_t hint = mi_atomic_add_acq_rel(&aligned_base, size);
if (hint == 0 || hint > ((intptr_t)30<<40)) { // try to wrap around after 30TiB (area after 32TiB is used for huge OS pages) if (hint == 0 || hint > KK_HINT_MAX) { // wrap or initialize
uintptr_t init = ((uintptr_t)4 << 40); // start at 4TiB area uintptr_t init = KK_HINT_BASE;
#if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of aligned allocations unless in debug mode #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of aligned allocations unless in debug mode
uintptr_t r = _mi_heap_random_next(mi_get_default_heap()); uintptr_t r = _mi_heap_random_next(mi_get_default_heap());
init = init + (MI_SEGMENT_SIZE * ((r>>17) & 0xFFFFF)); // (randomly 20 bits)*4MiB == 0 to 4TiB init = init + ((MI_SEGMENT_SIZE * ((r>>17) & 0xFFFFF)) % KK_HINT_AREA); // (randomly 20 bits)*4MiB == 0 to 4TiB
#endif #endif
uintptr_t expected = hint + size; uintptr_t expected = hint + size;
mi_atomic_cas_strong_acq_rel(&aligned_base, &expected, init); mi_atomic_cas_strong_acq_rel(&aligned_base, &expected, init);
hint = mi_atomic_add_acq_rel(&aligned_base, size); // this may still give 0 or > 30TiB but that is ok, it is a hint after all hint = mi_atomic_add_acq_rel(&aligned_base, size); // this may still give 0 or > KK_HINT_MAX but that is ok, it is a hint after all
} }
if (hint%try_alignment != 0) return NULL; if (hint%try_alignment != 0) return NULL;
return (void*)hint; return (void*)hint;

View File

@ -44,7 +44,7 @@ int main() {
padding_shrink(); padding_shrink();
various_tests(); various_tests();
large_alloc(); large_alloc();
test_mt_shutdown(); //test_mt_shutdown();
//fail_aslr(); //fail_aslr();
mi_stats_print(NULL); mi_stats_print(NULL);
return 0; return 0;
@ -230,5 +230,5 @@ void fail_aslr() {
size_t sz = (4ULL << 40); // 4TiB size_t sz = (4ULL << 40); // 4TiB
void* p = malloc(sz); void* p = malloc(sz);
printf("pointer p: %p: area up to %p\n", p, (uint8_t*)p + sz); printf("pointer p: %p: area up to %p\n", p, (uint8_t*)p + sz);
*(int*)0x7FFFFFFF000 = 0; // should segfault *(int*)0x5FFFFFFF000 = 0; // should segfault
} }