| 3765 | } |
| 3766 | |
| 3767 | static int sys_trim(mstate m, size_t pad, int force) { |
| 3768 | size_t released = 0; |
| 3769 | if (pad < MAX_REQUEST && is_initialized(m)) { |
| 3770 | pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ |
| 3771 | |
| 3772 | if (m->topsize > pad) { |
| 3773 | /* Shrink top space in granularity-size units, keeping at least one */ |
| 3774 | size_t unit = mparams.granularity; |
| 3775 | size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - |
| 3776 | SIZE_T_ONE) * unit; |
| 3777 | msegmentptr sp = segment_holding(m, (char*)m->top); |
| 3778 | |
| 3779 | if (force || !IS_RECENT(m, sp->base)) { |
| 3780 | if (!is_extern_segment(sp)) { |
| 3781 | if (is_allocfunc_segment(sp)) { |
| 3782 | if (m->reallocfunc != NULL && |
| 3783 | sp->size >= extra && |
| 3784 | !has_segment_link(m, sp) && (m->topsize + TOP_FOOT_SIZE == sp->size)) { |
| 3785 | /* |
| 3786 | ** Can't shrink if pinned or the segment is inuse. |
| 3787 | ** Realloc may copy memory around even if size is smaller. |
| 3788 | ** Thus shinking an in-use segment may cause addressing fault. |
| 3789 | ** Memory may be wasted here if only a small portion of top segment |
| 3790 | ** is inuse. |
| 3791 | */ |
| 3792 | size_t ofs = (char *)m->top - sp->base; |
| 3793 | size_t newsize = sp->size - extra; |
| 3794 | char *rebase; |
| 3795 | rebase = m->reallocfunc(sp->base, newsize); |
| 3796 | if (rebase != NULL) { |
| 3797 | if (rebase < m->least_addr) |
| 3798 | m->least_addr = rebase; |
| 3799 | m->top = (mchunkptr)(rebase + ofs); |
| 3800 | sp->base = rebase; |
| 3801 | released = extra; |
| 3802 | } |
| 3803 | } |
| 3804 | } |
| 3805 | else if (is_mmapped_segment(sp)) { |
| 3806 | if (HAVE_MMAP && |
| 3807 | sp->size >= extra && |
| 3808 | !has_segment_link(m, sp)) { /* can't shrink if pinned */ |
| 3809 | size_t newsize = sp->size - extra; |
| 3810 | /* Prefer mremap, fall back to munmap */ |
| 3811 | if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || |
| 3812 | (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { |
| 3813 | released = extra; |
| 3814 | } |
| 3815 | } |
| 3816 | } |
| 3817 | else if (HAVE_MORECORE) { |
| 3818 | if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ |
| 3819 | extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; |
| 3820 | ACQUIRE_MORECORE_LOCK(); |
| 3821 | { |
| 3822 | /* Make sure end of memory is where we last set it. */ |
| 3823 | char* old_br = (char*)(CALL_MORECORE(0)); |
| 3824 | if (old_br == sp->base + sp->size) { |
no test coverage detected