| 320 | #define MI_HINT_MAX ((uintptr_t)30 << 40) // wrap after 30TiB (area after 32TiB is used for huge OS pages) |
| 321 | |
| 322 | static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) |
| 323 | { |
| 324 | if (try_alignment <= 1 || try_alignment > MI_SEGMENT_SIZE) return NULL; |
| 325 | size = _mi_align_up(size, MI_SEGMENT_SIZE); |
| 326 | if (size > 1*MI_GiB) return NULL; // guarantee the chance of fixed valid address is at most 1/(MI_HINT_AREA / 1<<30) = 1/4096. |
| 327 | #if (MI_SECURE>0) |
| 328 | size += MI_SEGMENT_SIZE; // put in `MI_SEGMENT_SIZE` virtual gaps between hinted blocks; this splits VLA's but increases guarded areas. |
| 329 | #endif |
| 330 | |
| 331 | uintptr_t hint = mi_atomic_add_acq_rel(&aligned_base, size); |
| 332 | if (hint == 0 || hint > MI_HINT_MAX) { // wrap or initialize |
| 333 | uintptr_t init = MI_HINT_BASE; |
| 334 | #if (MI_SECURE>0 || MI_DEBUG==0) // security: randomize start of aligned allocations unless in debug mode |
| 335 | uintptr_t r = _mi_heap_random_next(mi_get_default_heap()); |
| 336 | init = init + ((MI_SEGMENT_SIZE * ((r>>17) & 0xFFFFF)) % MI_HINT_AREA); // (randomly 20 bits)*4MiB == 0 to 4TiB |
| 337 | #endif |
| 338 | uintptr_t expected = hint + size; |
| 339 | mi_atomic_cas_strong_acq_rel(&aligned_base, &expected, init); |
| 340 | hint = mi_atomic_add_acq_rel(&aligned_base, size); // this may still give 0 or > MI_HINT_MAX but that is ok, it is a hint after all |
| 341 | } |
| 342 | if (hint%try_alignment != 0) return NULL; |
| 343 | return (void*)hint; |
| 344 | } |
| 345 | #else |
| 346 | static void* mi_os_get_aligned_hint(size_t try_alignment, size_t size) { |
| 347 | MI_UNUSED(try_alignment); MI_UNUSED(size); |
no test coverage detected