Note: may still return NULL if committing the memory failed
| 674 | |
| 675 | // Note: may still return NULL if committing the memory failed |
| 676 | static mi_page_t* mi_segment_span_allocate(mi_segment_t* segment, size_t slice_index, size_t slice_count, mi_segments_tld_t* tld) { |
| 677 | mi_assert_internal(slice_index < segment->slice_entries); |
| 678 | mi_slice_t* const slice = &segment->slices[slice_index]; |
| 679 | mi_assert_internal(slice->xblock_size==0 || slice->xblock_size==1); |
| 680 | |
| 681 | // commit before changing the slice data |
| 682 | if (!mi_segment_ensure_committed(segment, _mi_segment_page_start_from_slice(segment, slice, 0, NULL), slice_count * MI_SEGMENT_SLICE_SIZE, tld->stats)) { |
| 683 | return NULL; // commit failed! |
| 684 | } |
| 685 | |
| 686 | // convert the slices to a page |
| 687 | slice->slice_offset = 0; |
| 688 | slice->slice_count = (uint32_t)slice_count; |
| 689 | mi_assert_internal(slice->slice_count == slice_count); |
| 690 | const size_t bsize = slice_count * MI_SEGMENT_SLICE_SIZE; |
| 691 | slice->xblock_size = (uint32_t)(bsize >= MI_HUGE_BLOCK_SIZE ? MI_HUGE_BLOCK_SIZE : bsize); |
| 692 | mi_page_t* page = mi_slice_to_page(slice); |
| 693 | mi_assert_internal(mi_page_block_size(page) == bsize); |
| 694 | |
| 695 | // set slice back pointers for the first MI_MAX_SLICE_OFFSET entries |
| 696 | size_t extra = slice_count-1; |
| 697 | if (extra > MI_MAX_SLICE_OFFSET) extra = MI_MAX_SLICE_OFFSET; |
| 698 | if (slice_index + extra >= segment->slice_entries) extra = segment->slice_entries - slice_index - 1; // huge objects may have more slices than avaiable entries in the segment->slices |
| 699 | |
| 700 | mi_slice_t* slice_next = slice + 1; |
| 701 | for (size_t i = 1; i <= extra; i++, slice_next++) { |
| 702 | slice_next->slice_offset = (uint32_t)(sizeof(mi_slice_t)*i); |
| 703 | slice_next->slice_count = 0; |
| 704 | slice_next->xblock_size = 1; |
| 705 | } |
| 706 | |
| 707 | // and also for the last one (if not set already) (the last one is needed for coalescing and for large alignments) |
| 708 | // note: the cast is needed for ubsan since the index can be larger than MI_SLICES_PER_SEGMENT for huge allocations (see #543) |
| 709 | mi_slice_t* last = slice + slice_count - 1; |
| 710 | mi_slice_t* end = (mi_slice_t*)mi_segment_slices_end(segment); |
| 711 | if (last > end) last = end; |
| 712 | if (last > slice) { |
| 713 | last->slice_offset = (uint32_t)(sizeof(mi_slice_t) * (last - slice)); |
| 714 | last->slice_count = 0; |
| 715 | last->xblock_size = 1; |
| 716 | } |
| 717 | |
| 718 | // and initialize the page |
| 719 | page->is_reset = false; |
| 720 | page->is_committed = true; |
| 721 | segment->used++; |
| 722 | return page; |
| 723 | } |
| 724 | |
| 725 | static void mi_segment_slice_split(mi_segment_t* segment, mi_slice_t* slice, size_t slice_count, mi_segments_tld_t* tld) { |
| 726 | mi_assert_internal(_mi_ptr_segment(slice) == segment); |
no test coverage detected