Get the segment data belonging to a pointer This is just a single `and` in assembly but does further checks in debug mode (and secure mode) if this was a valid pointer.
| 490 | // This is just a single `and` in assembly but does further checks in debug mode |
| 491 | // (and secure mode) if this was a valid pointer. |
| 492 | static inline mi_segment_t* mi_checked_ptr_segment(const void* p, const char* msg) |
| 493 | { |
| 494 | MI_UNUSED(msg); |
| 495 | mi_assert(p != NULL); |
| 496 | |
| 497 | #if (MI_DEBUG>0) |
| 498 | if mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0) { |
| 499 | _mi_error_message(EINVAL, "%s: invalid (unaligned) pointer: %p\n", msg, p); |
| 500 | return NULL; |
| 501 | } |
| 502 | #endif |
| 503 | |
| 504 | mi_segment_t* const segment = _mi_ptr_segment(p); |
| 505 | mi_assert_internal(segment != NULL); |
| 506 | |
| 507 | #if (MI_DEBUG>0) |
| 508 | if mi_unlikely(!mi_is_in_heap_region(p)) { |
| 509 | #if (MI_INTPTR_SIZE == 8 && defined(__linux__)) |
| 510 | if (((uintptr_t)p >> 40) != 0x7F) { // linux tends to align large blocks above 0x7F000000000 (issue #640) |
| 511 | #else |
| 512 | { |
| 513 | #endif |
| 514 | _mi_warning_message("%s: pointer might not point to a valid heap region: %p\n" |
| 515 | "(this may still be a valid very large allocation (over 64MiB))\n", msg, p); |
| 516 | if mi_likely(_mi_ptr_cookie(segment) == segment->cookie) { |
| 517 | _mi_warning_message("(yes, the previous pointer %p was valid after all)\n", p); |
| 518 | } |
| 519 | } |
| 520 | } |
| 521 | #endif |
| 522 | #if (MI_DEBUG>0 || MI_SECURE>=4) |
| 523 | if mi_unlikely(_mi_ptr_cookie(segment) != segment->cookie) { |
| 524 | _mi_error_message(EINVAL, "%s: pointer does not point to a valid heap space: %p\n", msg, p); |
| 525 | return NULL; |
| 526 | } |
| 527 | #endif |
| 528 | |
| 529 | return segment; |
| 530 | } |
| 531 | |
| 532 | // Free a block |
| 533 | // fast path written carefully to prevent spilling on the stack |
| 534 | void mi_free(void* p) mi_attr_noexcept |
| 535 | { |
| 536 | if mi_unlikely(p == NULL) return; |
| 537 | mi_segment_t* const segment = mi_checked_ptr_segment(p,"mi_free"); |
| 538 | const bool is_local= (_mi_thread_id() == mi_atomic_load_relaxed(&segment->thread_id)); |
| 539 | mi_page_t* const page = _mi_segment_page_of(segment, p); |
| 540 | |
| 541 | if mi_likely(is_local) { // thread-local free? |
| 542 | if mi_likely(page->flags.full_aligned == 0) // and it is not a full page (full pages need to move from the full bin), nor has aligned blocks (aligned blocks need to be unaligned) |
| 543 | { |
| 544 | mi_block_t* const block = (mi_block_t*)p; |
| 545 | if mi_unlikely(mi_check_is_double_free(page, block)) return; |
| 546 | mi_check_padding(page, block); |
| 547 | mi_stat_free(page, block); |
| 548 | #if (MI_DEBUG!=0) && !MI_TRACK_ENABLED |
| 549 | memset(block, MI_DEBUG_FREED, mi_page_block_size(page)); |
no test coverage detected