/* * The actual free() implementation. */ void free(void *x) { struct mheader *mh, *mhnext, *mhprev; if (x==NULL) { /* safest practice */ return; } /* Consistency check. */ if (__heapbase==0 || __heaptop==0 || __heapbase > __heaptop) { warnx("free: Internal error - local data corrupt"); errx(1, "free: heapbase 0x%lx; heaptop 0x%lx", (unsigned long) __heapbase, (unsigned long) __heaptop); } /* Don't allow freeing pointers that aren't on the heap. */ if ((uintptr_t)x < __heapbase || (uintptr_t)x >= __heaptop) { errx(1, "free: Invalid pointer %p freed (out of range)", x); } #ifdef MALLOCDEBUG warnx("free: about to free %p", x); __malloc_dump(); #endif mh = ((struct mheader *)x)-1; if (!M_OK(mh)) { errx(1, "free: Invalid pointer %p freed (corrupt header)", x); } if (!mh->mh_inuse) { errx(1, "free: Invalid pointer %p freed (already free)", x); } /* mark it free */ mh->mh_inuse = 0; /* wipe it */ __malloc_deadbeef(M_DATA(mh), M_SIZE(mh)); /* Try merging with the block above (but not if we're at the top) */ mhnext = M_NEXT(mh); if (mhnext != (struct mheader *)__heaptop) { __malloc_trymerge(mh, mhnext); } /* Try merging with the block below (but not if we're at the bottom) */ if (mh != (struct mheader *)__heapbase) { mhprev = M_PREV(mh); __malloc_trymerge(mhprev, mh); } #ifdef MALLOCDEBUG warnx("free: freed %p", x); __malloc_dump(); #endif }
/* * malloc: general-purpose storage allocator */ void * malloc(size_t nbytes) { Header *p, *prevp; unsigned nunits; nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1; MALLOC_LOCK; if ((prevp = freep) == NULL) { /* no free list yet */ base.s.ptr = freep = prevp = &base; base.s.size = 0; } for (p = prevp->s.ptr;; prevp = p, p = p->s.ptr) { if (p->s.size >= nunits) { /* big enough */ if (p->s.size == nunits) /* exactly */ prevp->s.ptr = p->s.ptr; else { /* allocate tail end */ p->s.size -= nunits; p += p->s.size; p->s.size = nunits; } freep = prevp; #ifdef CONFIG_MALLOC_DEBUG { /* Write bit pattern over data */ char *x = (char *) (p + 1); int i; for (i = 0; i < nbytes; i++) x[i] = 0xd0; } #endif #ifdef CONFIG_MALLOC_INSTRUMENT __malloc_instrumented_allocated += nunits; #endif #ifdef CONFIG_MALLOC_DEBUG_INTERNAL if (__malloc_check() != 0) { printf("malloc %d %p\n", nbytes, (void *) (p + 1)); __malloc_dump(); assert(__malloc_check() == 0); } #endif MALLOC_UNLOCK; return (void *) (p + 1); } if (p == freep) { /* wrapped around free list */ if ((p = (Header *) morecore(nunits)) == NULL) { MALLOC_UNLOCK; return NULL; /* none left */ } else { p->s.ptr = p; } } } MALLOC_UNLOCK; }
/* * free: put block ap in free list */ void free(void *ap) { Header *bp, *p; if (ap == NULL) return; MALLOC_LOCK; bp = (Header *) ap - 1; /* point to block header */ for (p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr) if (p >= p->s.ptr && (bp > p || bp < p->s.ptr)) break; /* freed block at start or end of arena */ #ifdef CONFIG_MALLOC_INSTRUMENT __malloc_instrumented_allocated -= bp->s.size; #endif if (bp + bp->s.size == p->s.ptr) { /* join to upper nbr */ bp->s.size += p->s.ptr->s.size; bp->s.ptr = p->s.ptr->s.ptr; } else { bp->s.ptr = p->s.ptr; } if (p + p->s.size == bp) { /* join to lower nbr */ p->s.size += bp->s.size; p->s.ptr = bp->s.ptr; } else { p->s.ptr = bp; } freep = p; #ifdef CONFIG_MALLOC_DEBUG_INTERNAL if (__malloc_check() != 0) { printf("free %p\n", ap); __malloc_dump(); assert(__malloc_check() == 0); } #endif MALLOC_UNLOCK; }
/* * malloc itself. */ void * malloc(size_t size) { struct mheader *mh; uintptr_t i; size_t rightprevblock; if (__heapbase==0) { __malloc_init(); } if (__heapbase==0 || __heaptop==0 || __heapbase > __heaptop) { warnx("malloc: Internal error - local data corrupt"); errx(1, "malloc: heapbase 0x%lx; heaptop 0x%lx", (unsigned long) __heapbase, (unsigned long) __heaptop); } #ifdef MALLOCDEBUG warnx("malloc: about to allocate %lu (0x%lx) bytes", (unsigned long) size, (unsigned long) size); __malloc_dump(); #endif /* Round size up to an integral number of blocks. */ size = ((size + MBLOCKSIZE - 1) & ~(size_t)(MBLOCKSIZE-1)); /* * First-fit search algorithm for available blocks. * Check to make sure the next/previous sizes all agree. */ rightprevblock = 0; for (i=__heapbase; i<__heaptop; i += M_NEXTOFF(mh)) { mh = (struct mheader *) i; if (!M_OK(mh)) { errx(1, "malloc: Heap corrupt; header at 0x%lx" " has bad magic bits", (unsigned long) i); } if (mh->mh_prevblock != rightprevblock) { errx(1, "malloc: Heap corrupt; header at 0x%lx" " has bad previous-block size %lu " "(should be %lu)", (unsigned long) i, (unsigned long) mh->mh_prevblock << MBLOCKSHIFT, (unsigned long) rightprevblock << MBLOCKSHIFT); } rightprevblock = mh->mh_nextblock; /* Can't allocate a block that's in use. */ if (mh->mh_inuse) { continue; } /* Can't allocate a block that isn't big enough. */ if (M_SIZE(mh) < size) { continue; } /* Try splitting block. */ __malloc_split(mh, size); /* * Now, allocate. */ mh->mh_inuse = 1; #ifdef MALLOCDEBUG warnx("malloc: allocating at %p", M_DATA(mh)); __malloc_dump(); #endif return M_DATA(mh); } if (i!=__heaptop) { errx(1, "malloc: Heap corrupt; ran off end"); } /* * Didn't find anything. Expand the heap. */ mh = __malloc_sbrk(size + MBLOCKSIZE); if (mh == NULL) { return NULL; } mh->mh_prevblock = rightprevblock; mh->mh_magic1 = MMAGIC; mh->mh_magic2 = MMAGIC; mh->mh_pad = 0; mh->mh_inuse = 1; mh->mh_nextblock = M_MKFIELD(size + MBLOCKSIZE); #ifdef MALLOCDEBUG warnx("malloc: allocating at %p", M_DATA(mh)); __malloc_dump(); #endif return M_DATA(mh); }