Exercise 8.7 - Error checking by malloc

Question

Malloc accepts a size request without checking its plausibility; free believes that the block it is asked to free contains a valid size field. Improve these routines so they make more pains with error checking.

/* malloc accepts a size request without checking its plausiblity; free believes
 that the block it is asked to free contain a valid size field. Improve these
 rountines so they take more pains with error checking */

#include <stdio.h>
#include <stdlib.h>

#define MAXBYTES (unsigned)10240
#define NALLOC 1024

typedef long Align;

union header {
    struct {
        union header *ptr; /* next block if on free list */
        unsigned size;     /* size of this block */
    } s;
};

typedef union header Header;

static unsigned maxalloc;    /* max number of units allocated */
static Header base;          /* empty list to get started */
static Header *freep = NULL; /*start of free list */

/* morecore: ask system for more memory */

static Header *morecore(unsigned nu) {
    char *cp, *sbrk(int);
    Header *up;

    if (nu < NALLOC)
        nu = NALLOC;

    cp = sbrk(nu * sizeof(Header));
    if (cp == (char *) -1) /* no space at all */
        return NULL;

    up = (Header *) cp;
    up->s.size = nu;
    free((void *) (up + 1));
    return freep;
}

/* malloc: general purpose storage allocator */

void *mymalloc(unsigned nbytes) {
    Header *p, *prevp;
    Header *morecore(unsigned);
    unsigned nunits;

    if (nbytes > MAXBYTES) {
        fprintf(stderr, "alloc: can't allocate more than %u bytes\n", MAXBYTES);
        return NULL;
    }
    nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;

    if ((prevp = freep) == NULL) {
        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) {
            if (p->s.size == nunits)
                prevp->s.ptr = p->s.ptr;
            else {
                p->s.size -= nunits;
                p += p->s.size;
                p->s.size = nunits;
            }
            freep = prevp;
            return (void *) (p + 1);
        }

        if (p == freep) /* wrapped around free list */
            if ((p = morecore(nunits)) == NULL)
                return NULL;
    }
}

/* free: put a block ap in free list */

void free(void *ap) {
    Header *bp, *p;

    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 */

    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;
}

int main(int argc, char *argv[]) {
    int *p = NULL;
    int i = 0;

    p = mymalloc(1000);
    if (NULL == p) {
        printf("mymalloc returned NULL");

    } else {
        for (i = 0; i <= 100; i++) {
            printf("%08X", p[i]);
            if (i % 8 == 7) {
                printf("\n");
            }
        }
        printf("\n");
        free(p);
    }
    return 0;
}

Explanation

This is an error checking implementation of malloc. If it cannot allocate more bytes, it will throw an error

if (nbytes > MAXBYTES) {
    fprintf(stderr, "alloc: can't allocate more than %u bytes\n", MAXBYTES);
    return NULL;
}