CSAPP: Malloc Lab 7

本次Lab真是CSAPP系列Lab中最恶心的Lab了!


这是《深入理解计算机系统》第二版配套Lab中的第7个Lab,对应本书的第9章:虚拟存储器。

下载地址:http://csapp.cs.cmu.edu/im/labs/malloclab.tar

Lab的要求是自己实现类似GNU Libc的malloc和free函数,也就是实现一个动态内存分配器,让你亲手管理一个程序的堆内存分配。最后会从吞吐量(单位时间可执行次数)和空间利用率两个方面进行评估。

本书中介绍了不少空闲链表的形式、分配策略,以及每个堆块的布局,诸如:

  1. 隐式空闲链表,只记录每个块的大小,分配时遍历整个堆寻找大小适合的块
  2. 显式空闲链表,在空闲块中额外记录前一个、后一个空闲块的位置,可以节省遍历时间
  3. 分离空闲链表,维护多个链表,将不同大小类的块分到同一个链表中
  • 首次适配:选择第一个合适的块
  • 下次适配:每次搜索从上次结束的地方开始
  • 最佳适配:选择大小合适的最小块
其他实现与堆块的布局在此就不赘述了~书上都有所介绍
这个Lab我整整做了4天多,前三天一直在Debug,直到最后一天才能正常运行,然后又花了几个小时优化才达到满分……

我的思路是空闲链表+BST:
  • 使用一小撮空闲链表来维护较小的空闲块
  • 使用二叉搜索树来维护大的空闲块链表
  • 所有的链表只存一种大小的空闲块
  • 具体如图所示,二叉搜索树的每个节点都是一个链表的头部


  • 优化策略:

    1、已分配的块可以省略脚部(Footer)。
    那么相邻空闲块合并时从何得知前一块是不是空闲呢?
    我们已经知道,块是按8字节对齐的,也就是说块头部中存储的块的大小是8的倍数,二进制表示中最后三位都是0。而在头部中,最低一位是存储当前块的分配状况的,那么就拿第二位来存储前一个块的分配情况好了。
    这样我们可以在合并时检查自己头部来得到前一块是不是被分配了,如果没有被分配,就与之合并。

    2、块指针可以用4字节保存。

    虽然在64位机器中,指针是64位的,不过由于本次Lab的writeup中指出

    Because we are running on 64-bit machines, your allocator must be coded accordingly, with one exception: the size of the heap will never be greater than or equal to 2^32 bytes. This does not imply anything about the location of the heap, but there is a neat optimization that can be done using this information. However, be very, very careful if you decide to take advantage of this fact.


    因而我们可以只记录每个地址相对于堆起始地址的偏移量,这个偏移量是32位的,这个改进可以使得块大小最小达到16字节!

    嗯……我也只想到了这么多,既然满分了就不再多想了……

    下附完整代码~
    里面有些宏函数的定义,显示起来可能略乱……

  • /* 
    * mm.c 
    * 
    * Name: LegendaryPaladin 
    * 姓名:轩辕奇侠 
    * 
    * Brief introduction: 
    *       This solution used an algorithm with segregated free list 
    *   and a binary search tree combined to maximize both space utilization 
    *   and throughput. Please note that each free list is a unique size class, 
    *   which means it only contains blocks with EXACTLY THE SAME SIZE. 
    *  
    * Details of binary search tree: 
    *       The BST is used to store free blocks sized larger than a specific 
    *   threshold (I set it to 40 bytes), of which each node is a header of a 
    *   free list of a same size, When searching for a free block in BST, 
    *   I applied the best-fit policy which selects the free block with 
    *   approximately minimum size among all the blocks sized larger than  
    *   requested. 
    * 
    * Details of segregated free list: 
    *       I set up a small array to store the headers of segregated free lists. 
    *   Each free list, as described above, has blocks with a same size. Blocks 
    *   which is not large enough to be stored in BST will be stored here. 
    * 
    * Block layout: 
    *       Allocated block: 
    * 
    *           [Header: <size><prev_alloc><1>] 
    *           [Payload...] 
    * 
    *       Large free block: 
    * 
    *           [Header: <size><prev_alloc><0>] 
    *           [4-byte pointer to next block with same size] 
    *           [4-byte pointer to previous block with same size] 
    *           [Pointer to its left child in BST] 
    *           [Pointer to its right child in BST] 
    *           [Pointer to the pointer to itself in its parent block in BST] 
    *           [...] 
    *           [Footer: <size><0>] 
    * 
    *       Small free block: 
    * 
    *           [Header: <size><prev_alloc><0>] 
    *           [4-byte pointer to next block with same size] 
    *           [4-byte pointer to previous block with same size] 
    *           [...] 
    *           [Footer: <size><0>] 
    * 
    *           Note that I omitted the footer of allocated block, instead, I 
    *       stored its allocation info in the header of next block. 
    * 
    * 
    * 概述: 
    *       本次作业,我通过分离空闲链表 + 二叉搜索树来实现空间利用率和效率的 
    *   最大化。注意我的每个链表都只存储一种大小的空闲块。 
    * 
    * 二叉搜索树: 
    *       二叉搜索树用于存大于某个特定阈值的块(我设为40字节),每个节点是 
    *   具有该大小的空闲块链表的表头。在树中查找结点的时候,我会使用“最优适配” 
    *   策略,选择树中大于请求大小的块中近似最小的那个。 
    * 
    * 分离空闲链表: 
    *       我给分离空闲链表的表头开了个小数组,每个空闲链表同样也只存一种大小的块。 
    *   大小不够放到树里的块会放到这里。 
    * 
    * 块布局: 
    *       已分配块: 
    * 
    *           [头部: <大小><上一块分配状况><1>] 
    *           [有效载荷...] 
    * 
    *       大的空闲块: 
    * 
    *           [头部: <大小><上一块分配状况><0>] 
    *           [指向下一个相同大小块的4字节指针] 
    *           [指向上一个相同大小块的4字节指针] 
    *           [指向左儿子的指针] 
    *           [指向右儿子的指针] 
    *           [指向它父亲指向它的指针的指针……] 
    *           [...] 
    *           [脚部: <大小><0>] 
    * 
    *       小的空闲块: 
    * 
    *           [头部: <大小><上一块分配状况><0>] 
    *           [指向下一个相同大小块的4字节指针] 
    *           [指向上一个相同大小块的4字节指针] 
    *           [...] 
    *           [脚部: <大小><0>] 
    * 
    *           注意我把已分配块的脚部省略了,把它的分配状态信息 
    *       存到了下一个块的头部。 
    * 
    */  
    #include <assert.h>  
    #include <stdio.h>  
    #include <stdlib.h>  
    #include <string.h>  
    #include <unistd.h>  
      
    /* Other helper headers */  
    #include <linux/kernel.h>  
    #include <linux/stddef.h>  
      
    #include "mm.h"  
    #include "memlib.h"  
      
    /* do not change the following! */  
    #ifdef DRIVER  
    /* create aliases for driver tests */  
    #define malloc mm_malloc  
    #define free mm_free  
    #define realloc mm_realloc  
    #define calloc mm_calloc  
    #endif /* def DRIVER */  
      
    typedef void *block_ptr;  
      
    /* Global var and data structure pointers */  
    static char *heap_listp = 0;        /* Pointer to first block */  
    static block_ptr larger_bin_root;   /* Root of the BST which contains larger blocks */  
    static block_ptr *bins;             /* Array of the headers of segregated free lists */  
    static const unsigned int fixed_bin_count = 5;  /* Number of segregated free lists */  
    #ifdef DEBUG  
    static int operid;  
    #endif  
      
    /* Function prototypes */  
    static block_ptr coalesce(block_ptr bp);  
    static block_ptr extend_heap(size_t words);  
    static void place(block_ptr bp, size_t asize);  
    static void insert_free_block(block_ptr bp, size_t blocksize);  
    static void printblock(block_ptr bp);  
    static void checkblock(block_ptr bp);  
    static block_ptr find_fit(size_t asize);  
    #ifdef DEBUG  
    static void printtree(block_ptr node, int depth);  
    #endif  
      
    /* Macros and utility inline functions */  
      
    /* Single word (4) or double word (8) alignment */  
    #define ALIGNMENT   8  
      
    /* Round size up to ALIGNMENT */  
    #define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~0x7)  
      
    /* Basic constants */  
    #define WSIZE       4           /* Word and header/footer size (bytes) */  
    #define DSIZE       8           /* Doubleword size (bytes) */  
    #define BLOCKSIZE   (1 << 6)  /* Extend heap by this amount (bytes) */  
      
    #define MAX(x, y) ((x) > (y)? (x) : (y))    
      
    /* Pack a size and allocated bit into a word */  
    #define PACK(size, alloc)   ((size) | (alloc))  
      
    /* Read and write a word at address p */  
    #define GET(p)              (*(unsigned int *)(p))  
    #define PUTTRUNC(p, val)    (GET(p) = (val))  
      
    /* Write header info at address p without modifying prev_alloc */  
    #define PUT(p, val)         (GET(p) = (GET(p) & 0x2) | (val))  
      
    /* Read the size and allocated fields from address p */  
    #define GET_SIZE(p)         (GET(p) & ~0x7)  
    #define GET_ALLOC(p)        (GET(p) & 0x1)  
      
    /* Given block ptr bp, compute address of its header and footer */  
    #define HDRP(bp)            ((char *)(bp) - WSIZE)  
    #define FTRP(bp)            ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)  
      
    /* Given block ptr bp, compute address of next and previous blocks */  
    #define NEXT_BLKP(bp)       ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE)))  
    #define PREV_BLKP(bp)       ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE)))  
      
    /* Given block ptr bp, set next block's prev_alloc */  
    #define SET_ALLOC(bp)       (GET(HDRP(NEXT_BLKP(bp))) |= 0x2)  
    #define SET_UNALLOC(bp)     (GET(HDRP(NEXT_BLKP(bp))) &= ~0x2)  
      
    /* Given block ptr bp, get prev_alloc */  
    #define GET_PREV_ALLOC(bp)  (GET(HDRP(bp)) & 0x2)  
      
    /* Given a freed block ptr bp, compute 'address' of next and previous blocks of same size */  
    #define NEXT_SAMESZ_BLKP(bp)    (*(unsigned int *)(bp))  
    #define PREV_SAMESZ_BLKP(bp)    (*(unsigned int *)((char *)(bp) + WSIZE))  
      
    #define WNULL 0U  
      
    /* Convert 4-byte address to 8-byte address */  
    static inline block_ptr word_to_ptr(unsigned int w)  
    {  
        return ((w) == WNULL ? NULL : (block_ptr)((unsigned int)(w) + 0x800000000UL));  
    }  
      
    /* Convert 8-byte address to 4-byte address */  
    static inline unsigned int ptr_to_word(block_ptr p)  
    {  
        return ((p) == NULL ? WNULL : (unsigned int)((unsigned long)(p) - 0x800000000UL));  
    }  
      
    /* The following are macros for BST node blocks */  
      
    /* Check if this block is large enough to be a BST node */  
    #define IS_OVER_BST_SIZE(size)  ((size) > DSIZE * fixed_bin_count)  
    #define IS_BST_NODE(bp)         (IS_OVER_BST_SIZE(GET_SIZE(HDRP(bp))))  
      
    /* Given BST block ptr bp, compute address of its left child or right child */  
    #define LCHLD_BLKPREF(bp)       ((block_ptr *)((char *)(bp) + DSIZE))  
    #define RCHLD_BLKPREF(bp)       ((block_ptr *)((char *)(bp) + DSIZE * 2))  
      
    /* Crap-like triple pointer > < */  
    #define PARENT_CHLDSLOTPREF(bp) ((block_ptr **)((char *)(bp) + DSIZE * 3))  
      
    #define LCHLD_BLKP(bp) (*LCHLD_BLKPREF(bp))  
    #define RCHLD_BLKP(bp) (*RCHLD_BLKPREF(bp))  
    #define PARENT_CHLDSLOTP(bp) (*PARENT_CHLDSLOTPREF(bp))  
      
    /* Reset the fields of a free block bp */  
    #define reset_block(bp)                                                     \  
    {                                                                           \  
        NEXT_SAMESZ_BLKP(bp) = WNULL;                                           \  
        PREV_SAMESZ_BLKP(bp) = WNULL;                                           \  
        if (IS_BST_NODE(bp))                                                    \  
        {                                                                       \  
            LCHLD_BLKP(bp) = NULL;                                              \  
            RCHLD_BLKP(bp) = NULL;                                              \  
            PARENT_CHLDSLOTP(bp) = NULL;                                        \  
        }                                                                       \  
    }  
      
    /* Remove bp from its free list */  
    #define remove_linked_freed_block(bp)                                               \  
    {                                                                                   \  
        if (PREV_SAMESZ_BLKP(bp))                                                       \  
            NEXT_SAMESZ_BLKP(word_to_ptr(PREV_SAMESZ_BLKP(bp))) = NEXT_SAMESZ_BLKP(bp); \  
        if (NEXT_SAMESZ_BLKP(bp))                                                       \  
            PREV_SAMESZ_BLKP(word_to_ptr(NEXT_SAMESZ_BLKP(bp))) = PREV_SAMESZ_BLKP(bp); \  
    }  
      
    static inline void remove_freed_block(block_ptr bp)  
    {  
        if (IS_BST_NODE(bp) && PARENT_CHLDSLOTP(bp))  
        {  
            /* I hate deleting node. */  
            block_ptr l = LCHLD_BLKP(bp), r = RCHLD_BLKP(bp), cur;  
            if ((cur = word_to_ptr(NEXT_SAMESZ_BLKP(bp))))  
            {  
                PARENT_CHLDSLOTP(cur) = PARENT_CHLDSLOTP(bp);  
                *PARENT_CHLDSLOTP(bp) = cur;  
                LCHLD_BLKP(cur) = l;  
                if (l)  
                    PARENT_CHLDSLOTP(l) = LCHLD_BLKPREF(cur);  
                RCHLD_BLKP(cur) = r;  
                if (r)  
                    PARENT_CHLDSLOTP(r) = RCHLD_BLKPREF(cur);  
            }  
            else if (l && r)  
            {  
                /* Find left-most node in right branch to replace curr */  
                if (!(cur = LCHLD_BLKP(r)))  
                {  
                    /* Right child doesn't have lchild */  
                    LCHLD_BLKP(r) = l;  
                    PARENT_CHLDSLOTP(r) = PARENT_CHLDSLOTP(bp);  
                    *PARENT_CHLDSLOTP(bp) = r;  
                    PARENT_CHLDSLOTP(l) = LCHLD_BLKPREF(r);  
                }  
                else  
                {  
                    while (LCHLD_BLKP(cur))  
                        cur = LCHLD_BLKP(cur);  
                    *PARENT_CHLDSLOTP(bp) = cur;  
                    *PARENT_CHLDSLOTP(cur) = RCHLD_BLKP(cur);  
                    if (RCHLD_BLKP(cur))  
                        PARENT_CHLDSLOTP(RCHLD_BLKP(cur)) = PARENT_CHLDSLOTP(cur);  
                    PARENT_CHLDSLOTP(cur) = PARENT_CHLDSLOTP(bp);  
                    LCHLD_BLKP(cur) = l;  
                    RCHLD_BLKP(cur) = r;  
                    PARENT_CHLDSLOTP(l) = LCHLD_BLKPREF(cur);  
                    PARENT_CHLDSLOTP(r) = RCHLD_BLKPREF(cur);  
                }  
            }  
            else if (r)  
            {  
                *PARENT_CHLDSLOTP(bp) = r;  
                PARENT_CHLDSLOTP(r) = PARENT_CHLDSLOTP(bp);  
            }  
            else if (l)  
            {  
                *PARENT_CHLDSLOTP(bp) = l;  
                PARENT_CHLDSLOTP(l) = PARENT_CHLDSLOTP(bp);  
            }  
            else  
                *PARENT_CHLDSLOTP(bp) = NULL;  
        }  
        else if (!PREV_SAMESZ_BLKP(bp))  
            /* Remove a free list header from the array of headers */  
            bins[GET_SIZE(HDRP(bp)) / DSIZE - 1] = word_to_ptr(NEXT_SAMESZ_BLKP(bp));  
        remove_linked_freed_block(bp);  
    }  
      
    /* Function definitions */  
      
    /* 
     * bestfit_search - search for a block with requested size or larger in BST. 
     */  
    block_ptr *bestfit_search(block_ptr *node, size_t size, int specific)  
    {  
        block_ptr *candidate, curr = *node;  
        size_t curr_size;  
      
        if (curr == NULL)  
            return NULL;  
      
        curr_size = GET_SIZE(HDRP(curr));  
      
        if (size < curr_size)  
        {  
            if (specific)  
                return bestfit_search(LCHLD_BLKPREF(curr), size, specific);  
            if ((candidate = bestfit_search(LCHLD_BLKPREF(curr), size, specific)))  
                return candidate;  
            return node;  
        }  
        else if (size > curr_size)  
            return bestfit_search(RCHLD_BLKPREF(curr), size, specific);  
        else  
            return node;  
    }  
      
    /* 
     * Return whether the pointer is in the heap. 
     * May be useful for debugging. 
     */  
    static inline int in_heap(const block_ptr p)  
    {  
        return p <= mem_heap_hi() && p >= mem_heap_lo();  
    }  
      
    /* 
     * Return whether the pointer is aligned. 
     * May be useful for debugging. 
     */  
    static inline int aligned(const block_ptr p)  
    {  
        return ((unsigned long)p % ALIGNMENT) == 0;  
    }  
      
    /* 
     * Initialize: return -1 on error, 0 on success. 
     */  
    int mm_init(void)  
    {  
        /* Create the initial empty heap */  
        if ((bins = mem_sbrk(  
            ALIGN(fixed_bin_count * sizeof(block_ptr)) +  
            4 * WSIZE)) == (block_ptr)-1)  
            return -1;  
        memset(bins, 0, fixed_bin_count * sizeof(block_ptr));  
        heap_listp = (char *)ALIGN((unsigned long)(bins + fixed_bin_count));  
        larger_bin_root = NULL;  
        PUTTRUNC(heap_listp, 0);                            /* Alignment padding */  
        PUTTRUNC(heap_listp + (1 * WSIZE), PACK(DSIZE, 1)); /* Prologue header */  
        PUTTRUNC(heap_listp + (2 * WSIZE), PACK(DSIZE, 1)); /* Prologue footer */  
        PUTTRUNC(heap_listp + (3 * WSIZE), PACK(0, 1));     /* Epilogue header */  
        heap_listp += (2 * WSIZE);  
        SET_ALLOC(heap_listp);  
    #ifdef DEBUG  
        {  
            printblock(heap_listp);  
            checkblock(heap_listp);  
        }  
        operid = 0;  
    #endif  
        return 0;  
    }  
      
    /* 
     * malloc 
     */  
    block_ptr malloc(size_t size)  
    {  
        size_t asize;      /* Adjusted block size */  
        size_t extendsize; /* Amount to extend heap if no fit */  
        char *bp;  
      
        if (heap_listp == 0)  
        {  
            mm_init();  
        }  
      
        /* Ignore spurious requests */  
        if (size == 0)  
            return NULL;  
      
      
        /* Adjust block size to include overhead and alignment reqs. */  
        if (size <= DSIZE)  
            asize = 2 * DSIZE;  
        else  
            asize = DSIZE * ((size + (WSIZE) + (DSIZE - 1)) / DSIZE);  
      
    #ifdef DEBUG  
        printf("\nMalloc request: size = %zu, rounded to %zu \033[41;37m[ID:%d]\033[0m\n", size, asize, operid++);  
    #endif  
      
        /* Search the free list for a fit */  
        if ((bp = find_fit(asize)) != NULL)  
        {  
    #ifdef DEBUG  
            {  
                puts("Found fit!");  
                checkblock(bp);  
                printblock(bp);  
            }  
    #endif  
            place(bp, asize);  
            return bp;  
        }  
      
        /* No fit found. Get more memory and place the block */  
        extendsize = MAX(asize, BLOCKSIZE);  
        if ((bp = extend_heap(extendsize / WSIZE)) == NULL)  
            return NULL;  
        place(bp, asize);  
        return bp;  
    }  
      
    /* 
     * free 
     */  
    void free(block_ptr ptr)  
    {  
        block_ptr tmp;  
        size_t size;  
        if (!ptr || !in_heap(ptr) || !aligned(ptr))  
            return;  
      
    #ifdef DEBUG  
        {  
            printf("\nFree request: ptr = %p \033[41;37m[ID:%d]\033[0m\n", ptr, operid++);  
            printblock(ptr);  
        }  
    #endif  
      
        size = GET_SIZE(HDRP(ptr));  
        PUT(HDRP(ptr), PACK(size, 0));  
        PUT(FTRP(ptr), PACK(size, 0));  
        SET_UNALLOC(ptr);  
        reset_block(ptr);  
        tmp = coalesce(ptr);  
        insert_free_block(tmp, GET_SIZE(HDRP(tmp)));  
    }  
      
    /* 
     * realloc - I don't want to look at mm-naive.c 
     */  
    block_ptr realloc(block_ptr oldptr, size_t size)  
    {  
        size_t oldsize;  
        block_ptr newptr;  
      
        /* If size == 0 then this is just free, and we return NULL. */  
        if (size == 0)  
        {  
            free(oldptr);  
            return 0;  
        }  
      
        /* If oldptr is NULL, then this is just malloc. */  
        if (oldptr == NULL)  
        {  
            return malloc(size);  
        }  
      
        newptr = malloc(size);  
      
        /* If realloc() fails the original block is left untouched  */  
        if (!newptr)  
        {  
            return 0;  
        }  
      
        /* Copy the old data. */  
        oldsize = GET_SIZE(HDRP(oldptr));  
        if (size < oldsize)  
            oldsize = size;  
        memcpy(newptr, oldptr, oldsize);  
      
        /* Free the old block. */  
        free(oldptr);  
      
        return newptr;  
    }  
      
    /* 
     * calloc - I don't want to look at mm-naive.c 
     * This function is not tested by mdriver, but it is 
     * needed to run the traces. 
     */  
    block_ptr calloc(size_t nmemb, size_t size)  
    {  
        size_t bytes = nmemb * size;  
        block_ptr newptr;  
      
        newptr = malloc(bytes);  
        memset(newptr, 0, bytes);  
      
        return newptr;  
    }  
      
    /* 
     * coalesce - Boundary tag coalescing. Return ptr to coalesced block 
     */  
    static block_ptr coalesce(block_ptr bp)  
    {  
        /*  
         * TODO Here is the bug: Do update the bins while doing this. 
         * Tried to fix. Not sure what will happen. 
         */  
        block_ptr prev, next = NEXT_BLKP(bp);  
      
        /* Use GET_PREV_ALLOC to judge if prev block is allocated */  
        size_t prev_alloc = GET_PREV_ALLOC(bp);  
        size_t next_alloc = GET_ALLOC(HDRP(next));  
        size_t size = GET_SIZE(HDRP(bp));  
      
        if (prev_alloc && next_alloc)            /* Case 1 */  
        {  
            return bp;  
        }  
      
        else if (prev_alloc && !next_alloc)      /* Case 2 */  
        {  
            remove_freed_block(next);  
            size += GET_SIZE(HDRP(next));  
            PUT(HDRP(bp), PACK(size, 0));  
            PUT(FTRP(bp), PACK(size, 0));  
        }  
      
        else if (!prev_alloc && next_alloc)       /* Case 3 */  
        {  
            prev = PREV_BLKP(bp);  
            remove_freed_block(prev);  
            size += GET_SIZE(HDRP(prev));  
            PUT(FTRP(bp), PACK(size, 0));  
            PUT(HDRP(prev), PACK(size, 0));  
            bp = prev;  
        }  
      
        else                                      /* Case 4 */  
        {  
            prev = PREV_BLKP(bp);  
            remove_freed_block(next);  
            remove_freed_block(prev);  
            size += GET_SIZE(HDRP(prev)) + GET_SIZE(FTRP(next));  
            PUT(HDRP(prev), PACK(size, 0));  
            PUT(FTRP(next), PACK(size, 0));  
            bp = prev;  
        }  
        reset_block(bp);  
        // insert_free_block(bp, size);  
        return bp;  
    }  
      
    /* 
     * extend_heap - Extend heap with free block and return its block pointer 
     */  
    static block_ptr extend_heap(size_t words)  
    {  
        char *bp;  
        size_t size;  
      
        /* Allocate an even number of words to maintain alignment */  
        size = (words % 2) ? (words + 1) * WSIZE : words * WSIZE;  
        if ((long)(bp = mem_sbrk(size)) == -1)  
            return NULL;  
      
    #ifdef DEBUG  
        printf("\nExtended the heap by %zu words.\n", words);  
    #endif  
      
        /* Initialize free block header/footer and the epilogue header */  
        PUT(HDRP(bp), PACK(size, 0));           /* Free block header */  
        PUT(FTRP(bp), PACK(size, 0));           /* Free block footer */  
        reset_block(bp);  
        PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1));   /* New epilogue header */  
      
        /* Coalesce if the previous block was free */  
        return coalesce(bp);  
    }  
      
    /* 
     * place - Place block of asize bytes at start of free block bp 
     *       and split if remainder would be at least minimum block size 
     */  
    static void place(block_ptr bp, size_t asize)  
    {  
        size_t csize = GET_SIZE(HDRP(bp)), delta = csize - asize;  
      
        if (delta >= (2 * DSIZE))  
        {  
            PUT(HDRP(bp), PACK(asize, 1));  
            PUT(FTRP(bp), PACK(asize, 1));  
            SET_ALLOC(bp);  
            bp = NEXT_BLKP(bp);  
            PUT(HDRP(bp), PACK(delta, 0));  
            PUT(FTRP(bp), PACK(delta, 0));  
            SET_UNALLOC(bp);  
            reset_block(bp);  
            insert_free_block(bp, delta);  
    #ifdef DEBUG  
            {  
                printf("Block with size %zu remains a block:\n", asize);  
                printblock(bp);  
            }  
    #endif  
        }  
        else  
        {  
            PUT(HDRP(bp), PACK(csize, 1));  
            PUT(FTRP(bp), PACK(csize, 1));  
            SET_ALLOC(bp);  
        }  
    }  
      
    /* 
     * insert_free_block - insert a block into BST or segregated free list 
     * BLOCKSIZE should be duplicate of double word 
     */  
    static void insert_free_block(block_ptr bp, size_t blocksize)  
    {  
        block_ptr *new = &larger_bin_root, parent = NULL;  
      
        if (!IS_OVER_BST_SIZE(blocksize))  
        {  
            /* Insert into segregated free list */  
            size_t dcount = blocksize / DSIZE;  
            if (bins[dcount - 1])  
            {  
                /* Connect it before the existing block as a new header */  
                NEXT_SAMESZ_BLKP(bp) = ptr_to_word(bins[dcount - 1]);  
                PREV_SAMESZ_BLKP(bins[dcount - 1]) = ptr_to_word(bp);  
            }  
            PREV_SAMESZ_BLKP(bp) = WNULL;  
            bins[dcount - 1] = bp;  
            return;  
        }  
      
        /* Figure out where to put the new node in BST */  
        while (*new)  
        {  
            size_t curr_size = GET_SIZE(HDRP(parent = *new));  
      
            if (blocksize < curr_size)  
                new = LCHLD_BLKPREF(parent);  
            else if (blocksize > curr_size)  
                new = RCHLD_BLKPREF(parent);  
            else  
            {  
                /* MWHAHAHAHAHA */  
                block_ptr next = word_to_ptr(NEXT_SAMESZ_BLKP(bp) = NEXT_SAMESZ_BLKP(parent));  
                if (next)  
                    /* Connect it before the existing block as a new header */  
                    PREV_SAMESZ_BLKP(next) = ptr_to_word(bp);  
                NEXT_SAMESZ_BLKP(parent) = ptr_to_word(bp);  
                PREV_SAMESZ_BLKP(bp) = ptr_to_word(parent);  
                return;  
            }  
        }  
      
        /* Connect this node as a child */  
        *new = bp;  
        PARENT_CHLDSLOTP(bp) = new;  
    #ifdef DEBUG  
        {  
            printf("Inserting a block: ");  
            printblock(bp);  
        }  
    #endif  
    }  
      
    /* 
     * find_fit - Find a fit for a block with asize bytes 
     * asize should be duplicate of double word 
     */  
    static block_ptr find_fit(size_t asize)  
    {  
        block_ptr curr, *blocks;  
        size_t dcount = asize / DSIZE;  
      
        if (!IS_OVER_BST_SIZE(asize))  
        {  
            if (bins[dcount - 1])  
            {  
                /* Found a free list of this size! */  
                curr = bins[dcount - 1];  
                bins[dcount - 1] = word_to_ptr(NEXT_SAMESZ_BLKP(curr));  
                remove_freed_block(curr);  
                return curr;  
            }  
            /* ...not found? Proceed to BST */  
        }  
      
        if ((blocks = bestfit_search(&larger_bin_root, asize, 0)) == NULL)  
            /* No best-fit found...T T */  
            return NULL;  
      
        curr = *blocks;  
      
        /* Found a best-fit block! LOL */  
    #ifdef DEBUG  
        if ((*blocks = word_to_ptr(NEXT_SAMESZ_BLKP(curr))) == NULL)  
        {  
            printf("** All blocks with size %u (request: %zu) deleted.\n", GET_SIZE(HDRP(curr)), asize);  
        }  
    #else  
        /* Set the node to the next same size block if it has */  
        *blocks = word_to_ptr(NEXT_SAMESZ_BLKP(curr));  
    #endif  
        remove_freed_block(curr);  
        return curr;  
    }  
      
    /* 
     * printblock - print a block for debugging 
     */  
    static inline void printblock(block_ptr bp)  
    {  
        size_t hsize, halloc, fsize, falloc;  
      
        hsize = GET_SIZE(HDRP(bp));  
        halloc = GET_ALLOC(HDRP(bp));  
        fsize = GET_SIZE(FTRP(bp));  
        falloc = GET_ALLOC(FTRP(bp));  
      
        if (hsize == 0)  
        {  
            printf("%p: EOL\n", bp);  
            return;  
        }  
        if (halloc)  
            printf("\033[43;37m%p: header: [%zu:%c:%c] footer: -\033[0m\n", bp,  
            hsize, (GET_PREV_ALLOC(bp) ? 'a' : 'f'), (halloc ? 'a' : 'f'));  
        else  
        {  
            printf("\033[42;30m%p: header: [%zu:%c:%c] footer: [%zu:%c]\033[0m", bp,  
                hsize, (GET_PREV_ALLOC(bp) ? 'a' : 'f'), (halloc ? 'a' : 'f'),  
                fsize, (falloc ? 'a' : 'f'));  
            if (IS_BST_NODE(bp))  
                printf("\033[1;44;33m[BST Node| parent slotp: %p, l: %p, r: %p]\033[0m",  
                PARENT_CHLDSLOTP(bp), LCHLD_BLKP(bp), RCHLD_BLKP(bp));  
            if (PREV_SAMESZ_BLKP(bp))  
                printf("\033[1;33m[PREV] %p\033[0m", word_to_ptr(PREV_SAMESZ_BLKP(bp)));  
            putchar('\n');  
        }  
    }  
      
    /* 
     * checkblock - as the name goes 
     */  
    static inline void checkblock(block_ptr bp)  
    {  
        if (!aligned(bp))  
            printf("\n\033[1;47;31m## Error: %p is not doubleword aligned\033[0m\n", bp);  
        if (!GET_ALLOC(HDRP(bp)) && (GET(HDRP(bp)) & ~0x2) != (GET(FTRP(bp)) & ~0x2))  
            printf("\n\033[1;47;31m## Error: header does not match footer, header: %u, footer: %u \033[0m\n",  
            GET(HDRP(bp)), GET(FTRP(bp)));  
        if (GET_ALLOC(HDRP(bp)) != (GET_PREV_ALLOC(NEXT_BLKP(bp)) >> 1))  
            printf("\n\033[1;47;31m## Error: %p allocation does not match next block's prev_alloc\033[0m\n", bp);  
    }  
      
    static void printchain(block_ptr node)  
    {  
        while (node)  
        {  
            printblock(node);  
            printf("->");  
            node = word_to_ptr(NEXT_SAMESZ_BLKP(node));  
        }  
    }  
      
    static void printtree(block_ptr node, int depth)  
    {  
        int i;  
        if (node == NULL)  
            return;  
        printf("BST: ");  
        for (i = 0; i < depth; i++)  
            putchar('-');  
        printchain(node);  
        putchar('\n');  
        printtree(LCHLD_BLKP(node), depth + 1);  
        printtree(RCHLD_BLKP(node), depth + 1);  
    }  
      
    static void checklist(block_ptr node)  
    {  
        if (node == NULL)  
            return;  
        if (PREV_SAMESZ_BLKP(node) &&  
            word_to_ptr(NEXT_SAMESZ_BLKP(word_to_ptr(PREV_SAMESZ_BLKP(node)))) != node)  
            printf("\n\033[1;47;31m## Bad neighbor pointer: %p\033[0m\n", node);  
        checklist(word_to_ptr(NEXT_SAMESZ_BLKP(node)));  
    }  
      
    static void checktree(block_ptr node)  
    {  
        if (node == NULL)  
            return;  
        if (*PARENT_CHLDSLOTP(node) != node)  
            printf("\n\033[1;47;31m## Bad parent pointer: %p\033[0m\n", node);  
        checklist(node);  
        checktree(LCHLD_BLKP(node));  
        checktree(RCHLD_BLKP(node));  
    }  
      
    /* 
     * checkheap - check the heap for consistency 
     */  
    void mm_checkheap(int verbose)  
    {  
        char *bp = heap_listp;  
      
        if (verbose)  
            printf("Heap (%p):\n", heap_listp);  
      
        if ((GET_SIZE(HDRP(heap_listp)) != DSIZE) || !GET_ALLOC(HDRP(heap_listp)))  
            printf("\n\033[1;47;31m## Bad prologue header\033[0m\n");  
        checkblock(heap_listp);  
      
        for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp))  
        {  
            if (verbose)  
                printblock(bp);  
            checkblock(bp);  
        }  
      
        if (verbose)  
        {  
            printblock(bp);  
            {  
                unsigned int i;  
                for (i = 1; i <= fixed_bin_count; i++)  
                if (bins[i - 1])  
                {  
                    printf("BIN #%d: size = %d ", i, i * DSIZE);  
                    checklist(bins[i - 1]);  
                    printchain(bins[i - 1]);  
                }  
                putchar('\n');  
                checktree(larger_bin_root);  
                printtree(larger_bin_root, 0);  
            }  
        }  
        if ((GET_SIZE(HDRP(bp)) != 0) || !(GET_ALLOC(HDRP(bp))))  
            printf("\n\033[1;47;31m## Bad epilogue header\033[0m\n");  
    }  

    /* 
    * mm.c 
    * 
    * Name: LegendaryPaladin 
    * 姓名:轩辕奇侠 
    * 
    * Brief introduction: 
    *       This solution used an algorithm with segregated free list 
    *   and a binary search tree combined to maximize both space utilization 
    *   and throughput. Please note that each free list is a unique size class, 
    *   which means it only contains blocks with EXACTLY THE SAME SIZE. 
    *  
    * Details of binary search tree: 
    *       The BST is used to store free blocks sized larger than a specific 
    *   threshold (I set it to 40 bytes), of which each node is a header of a 
    *   free list of a same size, When searching for a free block in BST, 
    *   I applied the best-fit policy which selects the free block with 
    *   approximately minimum size among all the blocks sized larger than  
    *   requested. 
    * 
    * Details of segregated free list: 
    *       I set up a small array to store the headers of segregated free lists. 
    *   Each free list, as described above, has blocks with a same size. Blocks 
    *   which is not large enough to be stored in BST will be stored here. 
    * 
    * Block layout: 
    *       Allocated block: 
    * 
    *           [Header: <size><prev_alloc><1>] 
    *           [Payload...] 
    * 
    *       Large free block: 
    * 
    *           [Header: <size><prev_alloc><0>] 
    *           [4-byte pointer to next block with same size] 
    *           [4-byte pointer to previous block with same size] 
    *           [Pointer to its left child in BST] 
    *           [Pointer to its right child in BST] 
    *           [Pointer to the pointer to itself in its parent block in BST] 
    *           [...] 
    *           [Footer: <size><0>] 
    * 
    *       Small free block: 
    * 
    *           [Header: <size><prev_alloc><0>] 
    *           [4-byte pointer to next block with same size] 
    *           [4-byte pointer to previous block with same size] 
    *           [...] 
    *           [Footer: <size><0>] 
    * 
    *           Note that I omitted the footer of allocated block, instead, I 
    *       stored its allocation info in the header of next block. 
    * 
    * 
    * 概述: 
    *       本次作业,我通过分离空闲链表 + 二叉搜索树来实现空间利用率和效率的 
    *   最大化。注意我的每个链表都只存储一种大小的空闲块。 
    * 
    * 二叉搜索树: 
    *       二叉搜索树用于存大于某个特定阈值的块(我设为40字节),每个节点是 
    *   具有该大小的空闲块链表的表头。在树中查找结点的时候,我会使用“最优适配” 
    *   策略,选择树中大于请求大小的块中近似最小的那个。 
    * 
    * 分离空闲链表: 
    *       我给分离空闲链表的表头开了个小数组,每个空闲链表同样也只存一种大小的块。 
    *   大小不够放到树里的块会放到这里。 
    * 
    * 块布局: 
    *       已分配块: 
    * 
    *           [头部: <大小><上一块分配状况><1>] 
    *           [有效载荷...] 
    * 
    *       大的空闲块: 
    * 
    *           [头部: <大小><上一块分配状况><0>] 
    *           [指向下一个相同大小块的4字节指针] 
    *           [指向上一个相同大小块的4字节指针] 
    *           [指向左儿子的指针] 
    *           [指向右儿子的指针] 
    *           [指向它父亲指向它的指针的指针……] 
    *           [...] 
    *           [脚部: <大小><0>] 
    * 
    *       小的空闲块: 
    * 
    *           [头部: <大小><上一块分配状况><0>] 
    *           [指向下一个相同大小块的4字节指针] 
    *           [指向上一个相同大小块的4字节指针] 
    *           [...] 
    *           [脚部: <大小><0>] 
    * 
    *           注意我把已分配块的脚部省略了,把它的分配状态信息 
    *       存到了下一个块的头部。 
    * 
    */  
    #include <assert.h>  
    #include <stdio.h>  
    #include <stdlib.h>  
    #include <string.h>  
    #include <unistd.h>  
      
    /* Other helper headers */  
    #include <linux/kernel.h>  
    #include <linux/stddef.h>  
      
    #include "mm.h"  
    #include "memlib.h"  
      
    /* do not change the following! */  
    #ifdef DRIVER  
    /* create aliases for driver tests */  
    #define malloc mm_malloc  
    #define free mm_free  
    #define realloc mm_realloc  
    #define calloc mm_calloc  
    #endif /* def DRIVER */  
      
    typedef void *block_ptr;  
      
    /* Global var and data structure pointers */  
    static char *heap_listp = 0;        /* Pointer to first block */  
    static block_ptr larger_bin_root;   /* Root of the BST which contains larger blocks */  
    static block_ptr *bins;             /* Array of the headers of segregated free lists */  
    static const unsigned int fixed_bin_count = 5;  /* Number of segregated free lists */  
    #ifdef DEBUG  
    static int operid;  
    #endif  
      
    /* Function prototypes */  
    static block_ptr coalesce(block_ptr bp);  
    static block_ptr extend_heap(size_t words);  
    static void place(block_ptr bp, size_t asize);  
    static void insert_free_block(block_ptr bp, size_t blocksize);  
    static void printblock(block_ptr bp);  
    static void checkblock(block_ptr bp);  
    static block_ptr find_fit(size_t asize);  
    #ifdef DEBUG  
    static void printtree(block_ptr node, int depth);  
    #endif  
      
    /* Macros and utility inline functions */  
      
    /* Single word (4) or double word (8) alignment */  
    #define ALIGNMENT   8  
      
    /* Round size up to ALIGNMENT */  
    #define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~0x7)  
      
    /* Basic constants */  
    #define WSIZE       4           /* Word and header/footer size (bytes) */  
    #define DSIZE       8           /* Doubleword size (bytes) */  
    #define BLOCKSIZE   (1 << 6)  /* Extend heap by this amount (bytes) */  
      
    #define MAX(x, y) ((x) > (y)? (x) : (y))    
      
    /* Pack a size and allocated bit into a word */  
    #define PACK(size, alloc)   ((size) | (alloc))  
      
    /* Read and write a word at address p */  
    #define GET(p)              (*(unsigned int *)(p))  
    #define PUTTRUNC(p, val)    (GET(p) = (val))  
      
    /* Write header info at address p without modifying prev_alloc */  
    #define PUT(p, val)         (GET(p) = (GET(p) & 0x2) | (val))  
      
    /* Read the size and allocated fields from address p */  
    #define GET_SIZE(p)         (GET(p) & ~0x7)  
    #define GET_ALLOC(p)        (GET(p) & 0x1)  
      
    /* Given block ptr bp, compute address of its header and footer */  
    #define HDRP(bp)            ((char *)(bp) - WSIZE)  
    #define FTRP(bp)            ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)  
      
    /* Given block ptr bp, compute address of next and previous blocks */  
    #define NEXT_BLKP(bp)       ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE)))  
    #define PREV_BLKP(bp)       ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE)))  
      
    /* Given block ptr bp, set next block's prev_alloc */  
    #define SET_ALLOC(bp)       (GET(HDRP(NEXT_BLKP(bp))) |= 0x2)  
    #define SET_UNALLOC(bp)     (GET(HDRP(NEXT_BLKP(bp))) &= ~0x2)  
      
    /* Given block ptr bp, get prev_alloc */  
    #define GET_PREV_ALLOC(bp)  (GET(HDRP(bp)) & 0x2)  
      
    /* Given a freed block ptr bp, compute 'address' of next and previous blocks of same size */  
    #define NEXT_SAMESZ_BLKP(bp)    (*(unsigned int *)(bp))  
    #define PREV_SAMESZ_BLKP(bp)    (*(unsigned int *)((char *)(bp) + WSIZE))  
      
    #define WNULL 0U  
      
    /* Convert 4-byte address to 8-byte address */  
    static inline block_ptr word_to_ptr(unsigned int w)  
    {  
        return ((w) == WNULL ? NULL : (block_ptr)((unsigned int)(w) + 0x800000000UL));  
    }  
      
    /* Convert 8-byte address to 4-byte address */  
    static inline unsigned int ptr_to_word(block_ptr p)  
    {  
        return ((p) == NULL ? WNULL : (unsigned int)((unsigned long)(p) - 0x800000000UL));  
    }  
      
    /* The following are macros for BST node blocks */  
      
    /* Check if this block is large enough to be a BST node */  
    #define IS_OVER_BST_SIZE(size)  ((size) > DSIZE * fixed_bin_count)  
    #define IS_BST_NODE(bp)         (IS_OVER_BST_SIZE(GET_SIZE(HDRP(bp))))  
      
    /* Given BST block ptr bp, compute address of its left child or right child */  
    #define LCHLD_BLKPREF(bp)       ((block_ptr *)((char *)(bp) + DSIZE))  
    #define RCHLD_BLKPREF(bp)       ((block_ptr *)((char *)(bp) + DSIZE * 2))  
      
    /* Crap-like triple pointer > < */  
    #define PARENT_CHLDSLOTPREF(bp) ((block_ptr **)((char *)(bp) + DSIZE * 3))  
      
    #define LCHLD_BLKP(bp) (*LCHLD_BLKPREF(bp))  
    #define RCHLD_BLKP(bp) (*RCHLD_BLKPREF(bp))  
    #define PARENT_CHLDSLOTP(bp) (*PARENT_CHLDSLOTPREF(bp))  
      
    /* Reset the fields of a free block bp */  
    #define reset_block(bp)                                                     \  
    {                                                                           \  
        NEXT_SAMESZ_BLKP(bp) = WNULL;                                           \  
        PREV_SAMESZ_BLKP(bp) = WNULL;                                           \  
        if (IS_BST_NODE(bp))                                                    \  
        {                                                                       \  
            LCHLD_BLKP(bp) = NULL;                                              \  
            RCHLD_BLKP(bp) = NULL;                                              \  
            PARENT_CHLDSLOTP(bp) = NULL;                                        \  
        }                                                                       \  
    }  
      
    /* Remove bp from its free list */  
    #define remove_linked_freed_block(bp)                                               \  
    {                                                                                   \  
        if (PREV_SAMESZ_BLKP(bp))                                                       \  
            NEXT_SAMESZ_BLKP(word_to_ptr(PREV_SAMESZ_BLKP(bp))) = NEXT_SAMESZ_BLKP(bp); \  
        if (NEXT_SAMESZ_BLKP(bp))                                                       \  
            PREV_SAMESZ_BLKP(word_to_ptr(NEXT_SAMESZ_BLKP(bp))) = PREV_SAMESZ_BLKP(bp); \  
    }  
      
    static inline void remove_freed_block(block_ptr bp)  
    {  
        if (IS_BST_NODE(bp) && PARENT_CHLDSLOTP(bp))  
        {  
            /* I hate deleting node. */  
            block_ptr l = LCHLD_BLKP(bp), r = RCHLD_BLKP(bp), cur;  
            if ((cur = word_to_ptr(NEXT_SAMESZ_BLKP(bp))))  
            {  
                PARENT_CHLDSLOTP(cur) = PARENT_CHLDSLOTP(bp);  
                *PARENT_CHLDSLOTP(bp) = cur;  
                LCHLD_BLKP(cur) = l;  
                if (l)  
                    PARENT_CHLDSLOTP(l) = LCHLD_BLKPREF(cur);  
                RCHLD_BLKP(cur) = r;  
                if (r)  
                    PARENT_CHLDSLOTP(r) = RCHLD_BLKPREF(cur);  
            }  
            else if (l && r)  
            {  
                /* Find left-most node in right branch to replace curr */  
                if (!(cur = LCHLD_BLKP(r)))  
                {  
                    /* Right child doesn't have lchild */  
                    LCHLD_BLKP(r) = l;  
                    PARENT_CHLDSLOTP(r) = PARENT_CHLDSLOTP(bp);  
                    *PARENT_CHLDSLOTP(bp) = r;  
                    PARENT_CHLDSLOTP(l) = LCHLD_BLKPREF(r);  
                }  
                else  
                {  
                    while (LCHLD_BLKP(cur))  
                        cur = LCHLD_BLKP(cur);  
                    *PARENT_CHLDSLOTP(bp) = cur;  
                    *PARENT_CHLDSLOTP(cur) = RCHLD_BLKP(cur);  
                    if (RCHLD_BLKP(cur))  
                        PARENT_CHLDSLOTP(RCHLD_BLKP(cur)) = PARENT_CHLDSLOTP(cur);  
                    PARENT_CHLDSLOTP(cur) = PARENT_CHLDSLOTP(bp);  
                    LCHLD_BLKP(cur) = l;  
                    RCHLD_BLKP(cur) = r;  
                    PARENT_CHLDSLOTP(l) = LCHLD_BLKPREF(cur);  
                    PARENT_CHLDSLOTP(r) = RCHLD_BLKPREF(cur);  
                }  
            }  
            else if (r)  
            {  
                *PARENT_CHLDSLOTP(bp) = r;  
                PARENT_CHLDSLOTP(r) = PARENT_CHLDSLOTP(bp);  
            }  
            else if (l)  
            {  
                *PARENT_CHLDSLOTP(bp) = l;  
                PARENT_CHLDSLOTP(l) = PARENT_CHLDSLOTP(bp);  
            }  
            else  
                *PARENT_CHLDSLOTP(bp) = NULL;  
        }  
        else if (!PREV_SAMESZ_BLKP(bp))  
            /* Remove a free list header from the array of headers */  
            bins[GET_SIZE(HDRP(bp)) / DSIZE - 1] = word_to_ptr(NEXT_SAMESZ_BLKP(bp));  
        remove_linked_freed_block(bp);  
    }  
      
    /* Function definitions */  
      
    /* 
     * bestfit_search - search for a block with requested size or larger in BST. 
     */  
    block_ptr *bestfit_search(block_ptr *node, size_t size, int specific)  
    {  
        block_ptr *candidate, curr = *node;  
        size_t curr_size;  
      
        if (curr == NULL)  
            return NULL;  
      
        curr_size = GET_SIZE(HDRP(curr));  
      
        if (size < curr_size)  
        {  
            if (specific)  
                return bestfit_search(LCHLD_BLKPREF(curr), size, specific);  
            if ((candidate = bestfit_search(LCHLD_BLKPREF(curr), size, specific)))  
                return candidate;  
            return node;  
        }  
        else if (size > curr_size)  
            return bestfit_search(RCHLD_BLKPREF(curr), size, specific);  
        else  
            return node;  
    }  
      
    /* 
     * Return whether the pointer is in the heap. 
     * May be useful for debugging. 
     */  
    static inline int in_heap(const block_ptr p)  
    {  
        return p <= mem_heap_hi() && p >= mem_heap_lo();  
    }  
      
    /* 
     * Return whether the pointer is aligned. 
     * May be useful for debugging. 
     */  
    static inline int aligned(const block_ptr p)  
    {  
        return ((unsigned long)p % ALIGNMENT) == 0;  
    }  
      
    /* 
     * Initialize: return -1 on error, 0 on success. 
     */  
    int mm_init(void)  
    {  
        /* Create the initial empty heap */  
        if ((bins = mem_sbrk(  
            ALIGN(fixed_bin_count * sizeof(block_ptr)) +  
            4 * WSIZE)) == (block_ptr)-1)  
            return -1;  
        memset(bins, 0, fixed_bin_count * sizeof(block_ptr));  
        heap_listp = (char *)ALIGN((unsigned long)(bins + fixed_bin_count));  
        larger_bin_root = NULL;  
        PUTTRUNC(heap_listp, 0);                            /* Alignment padding */  
        PUTTRUNC(heap_listp + (1 * WSIZE), PACK(DSIZE, 1)); /* Prologue header */  
        PUTTRUNC(heap_listp + (2 * WSIZE), PACK(DSIZE, 1)); /* Prologue footer */  
        PUTTRUNC(heap_listp + (3 * WSIZE), PACK(0, 1));     /* Epilogue header */  
        heap_listp += (2 * WSIZE);  
        SET_ALLOC(heap_listp);  
    #ifdef DEBUG  
        {  
            printblock(heap_listp);  
            checkblock(heap_listp);  
        }  
        operid = 0;  
    #endif  
        return 0;  
    }  
      
    /* 
     * malloc 
     */  
    block_ptr malloc(size_t size)  
    {  
        size_t asize;      /* Adjusted block size */  
        size_t extendsize; /* Amount to extend heap if no fit */  
        char *bp;  
      
        if (heap_listp == 0)  
        {  
            mm_init();  
        }  
      
        /* Ignore spurious requests */  
        if (size == 0)  
            return NULL;  
      
      
        /* Adjust block size to include overhead and alignment reqs. */  
        if (size <= DSIZE)  
            asize = 2 * DSIZE;  
        else  
            asize = DSIZE * ((size + (WSIZE) + (DSIZE - 1)) / DSIZE);  
      
    #ifdef DEBUG  
        printf("\nMalloc request: size = %zu, rounded to %zu \033[41;37m[ID:%d]\033[0m\n", size, asize, operid++);  
    #endif  
      
        /* Search the free list for a fit */  
        if ((bp = find_fit(asize)) != NULL)  
        {  
    #ifdef DEBUG  
            {  
                puts("Found fit!");  
                checkblock(bp);  
                printblock(bp);  
            }  
    #endif  
            place(bp, asize);  
            return bp;  
        }  
      
        /* No fit found. Get more memory and place the block */  
        extendsize = MAX(asize, BLOCKSIZE);  
        if ((bp = extend_heap(extendsize / WSIZE)) == NULL)  
            return NULL;  
        place(bp, asize);  
        return bp;  
    }  
      
    /* 
     * free 
     */  
    void free(block_ptr ptr)  
    {  
        block_ptr tmp;  
        size_t size;  
        if (!ptr || !in_heap(ptr) || !aligned(ptr))  
            return;  
      
    #ifdef DEBUG  
        {  
            printf("\nFree request: ptr = %p \033[41;37m[ID:%d]\033[0m\n", ptr, operid++);  
            printblock(ptr);  
        }  
    #endif  
      
        size = GET_SIZE(HDRP(ptr));  
        PUT(HDRP(ptr), PACK(size, 0));  
        PUT(FTRP(ptr), PACK(size, 0));  
        SET_UNALLOC(ptr);  
        reset_block(ptr);  
        tmp = coalesce(ptr);  
        insert_free_block(tmp, GET_SIZE(HDRP(tmp)));  
    }  
      
    /* 
     * realloc - I don't want to look at mm-naive.c 
     */  
    block_ptr realloc(block_ptr oldptr, size_t size)  
    {  
        size_t oldsize;  
        block_ptr newptr;  
      
        /* If size == 0 then this is just free, and we return NULL. */  
        if (size == 0)  
        {  
            free(oldptr);  
            return 0;  
        }  
      
        /* If oldptr is NULL, then this is just malloc. */  
        if (oldptr == NULL)  
        {  
            return malloc(size);  
        }  
      
        newptr = malloc(size);  
      
        /* If realloc() fails the original block is left untouched  */  
        if (!newptr)  
        {  
            return 0;  
        }  
      
        /* Copy the old data. */  
        oldsize = GET_SIZE(HDRP(oldptr));  
        if (size < oldsize)  
            oldsize = size;  
        memcpy(newptr, oldptr, oldsize);  
      
        /* Free the old block. */  
        free(oldptr);  
      
        return newptr;  
    }  
      
    /* 
     * calloc - I don't want to look at mm-naive.c 
     * This function is not tested by mdriver, but it is 
     * needed to run the traces. 
     */  
    block_ptr calloc(size_t nmemb, size_t size)  
    {  
        size_t bytes = nmemb * size;  
        block_ptr newptr;  
      
        newptr = malloc(bytes);  
        memset(newptr, 0, bytes);  
      
        return newptr;  
    }  
      
    /* 
     * coalesce - Boundary tag coalescing. Return ptr to coalesced block 
     */  
    static block_ptr coalesce(block_ptr bp)  
    {  
        /*  
         * TODO Here is the bug: Do update the bins while doing this. 
         * Tried to fix. Not sure what will happen. 
         */  
        block_ptr prev, next = NEXT_BLKP(bp);  
      
        /* Use GET_PREV_ALLOC to judge if prev block is allocated */  
        size_t prev_alloc = GET_PREV_ALLOC(bp);  
        size_t next_alloc = GET_ALLOC(HDRP(next));  
        size_t size = GET_SIZE(HDRP(bp));  
      
        if (prev_alloc && next_alloc)            /* Case 1 */  
        {  
            return bp;  
        }  
      
        else if (prev_alloc && !next_alloc)      /* Case 2 */  
        {  
            remove_freed_block(next);  
            size += GET_SIZE(HDRP(next));  
            PUT(HDRP(bp), PACK(size, 0));  
            PUT(FTRP(bp), PACK(size, 0));  
        }  
      
        else if (!prev_alloc && next_alloc)       /* Case 3 */  
        {  
            prev = PREV_BLKP(bp);  
            remove_freed_block(prev);  
            size += GET_SIZE(HDRP(prev));  
            PUT(FTRP(bp), PACK(size, 0));  
            PUT(HDRP(prev), PACK(size, 0));  
            bp = prev;  
        }  
      
        else                                      /* Case 4 */  
        {  
            prev = PREV_BLKP(bp);  
            remove_freed_block(next);  
            remove_freed_block(prev);  
            size += GET_SIZE(HDRP(prev)) + GET_SIZE(FTRP(next));  
            PUT(HDRP(prev), PACK(size, 0));  
            PUT(FTRP(next), PACK(size, 0));  
            bp = prev;  
        }  
        reset_block(bp);  
        // insert_free_block(bp, size);  
        return bp;  
    }  
      
    /* 
     * extend_heap - Extend heap with free block and return its block pointer 
     */  
    static block_ptr extend_heap(size_t words)  
    {  
        char *bp;  
        size_t size;  
      
        /* Allocate an even number of words to maintain alignment */  
        size = (words % 2) ? (words + 1) * WSIZE : words * WSIZE;  
        if ((long)(bp = mem_sbrk(size)) == -1)  
            return NULL;  
      
    #ifdef DEBUG  
        printf("\nExtended the heap by %zu words.\n", words);  
    #endif  
      
        /* Initialize free block header/footer and the epilogue header */  
        PUT(HDRP(bp), PACK(size, 0));           /* Free block header */  
        PUT(FTRP(bp), PACK(size, 0));           /* Free block footer */  
        reset_block(bp);  
        PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1));   /* New epilogue header */  
      
        /* Coalesce if the previous block was free */  
        return coalesce(bp);  
    }  
      
    /* 
     * place - Place block of asize bytes at start of free block bp 
     *       and split if remainder would be at least minimum block size 
     */  
    static void place(block_ptr bp, size_t asize)  
    {  
        size_t csize = GET_SIZE(HDRP(bp)), delta = csize - asize;  
      
        if (delta >= (2 * DSIZE))  
        {  
            PUT(HDRP(bp), PACK(asize, 1));  
            PUT(FTRP(bp), PACK(asize, 1));  
            SET_ALLOC(bp);  
            bp = NEXT_BLKP(bp);  
            PUT(HDRP(bp), PACK(delta, 0));  
            PUT(FTRP(bp), PACK(delta, 0));  
            SET_UNALLOC(bp);  
            reset_block(bp);  
            insert_free_block(bp, delta);  
    #ifdef DEBUG  
            {  
                printf("Block with size %zu remains a block:\n", asize);  
                printblock(bp);  
            }  
    #endif  
        }  
        else  
        {  
            PUT(HDRP(bp), PACK(csize, 1));  
            PUT(FTRP(bp), PACK(csize, 1));  
            SET_ALLOC(bp);  
        }  
    }  
      
    /* 
     * insert_free_block - insert a block into BST or segregated free list 
     * BLOCKSIZE should be duplicate of double word 
     */  
    static void insert_free_block(block_ptr bp, size_t blocksize)  
    {  
        block_ptr *new = &larger_bin_root, parent = NULL;  
      
        if (!IS_OVER_BST_SIZE(blocksize))  
        {  
            /* Insert into segregated free list */  
            size_t dcount = blocksize / DSIZE;  
            if (bins[dcount - 1])  
            {  
                /* Connect it before the existing block as a new header */  
                NEXT_SAMESZ_BLKP(bp) = ptr_to_word(bins[dcount - 1]);  
                PREV_SAMESZ_BLKP(bins[dcount - 1]) = ptr_to_word(bp);  
            }  
            PREV_SAMESZ_BLKP(bp) = WNULL;  
            bins[dcount - 1] = bp;  
            return;  
        }  
      
        /* Figure out where to put the new node in BST */  
        while (*new)  
        {  
            size_t curr_size = GET_SIZE(HDRP(parent = *new));  
      
            if (blocksize < curr_size)  
                new = LCHLD_BLKPREF(parent);  
            else if (blocksize > curr_size)  
                new = RCHLD_BLKPREF(parent);  
            else  
            {  
                /* MWHAHAHAHAHA */  
                block_ptr next = word_to_ptr(NEXT_SAMESZ_BLKP(bp) = NEXT_SAMESZ_BLKP(parent));  
                if (next)  
                    /* Connect it before the existing block as a new header */  
                    PREV_SAMESZ_BLKP(next) = ptr_to_word(bp);  
                NEXT_SAMESZ_BLKP(parent) = ptr_to_word(bp);  
                PREV_SAMESZ_BLKP(bp) = ptr_to_word(parent);  
                return;  
            }  
        }  
      
        /* Connect this node as a child */  
        *new = bp;  
        PARENT_CHLDSLOTP(bp) = new;  
    #ifdef DEBUG  
        {  
            printf("Inserting a block: ");  
            printblock(bp);  
        }  
    #endif  
    }  
      
    /* 
     * find_fit - Find a fit for a block with asize bytes 
     * asize should be duplicate of double word 
     */  
    static block_ptr find_fit(size_t asize)  
    {  
        block_ptr curr, *blocks;  
        size_t dcount = asize / DSIZE;  
      
        if (!IS_OVER_BST_SIZE(asize))  
        {  
            if (bins[dcount - 1])  
            {  
                /* Found a free list of this size! */  
                curr = bins[dcount - 1];  
                bins[dcount - 1] = word_to_ptr(NEXT_SAMESZ_BLKP(curr));  
                remove_freed_block(curr);  
                return curr;  
            }  
            /* ...not found? Proceed to BST */  
        }  
      
        if ((blocks = bestfit_search(&larger_bin_root, asize, 0)) == NULL)  
            /* No best-fit found...T T */  
            return NULL;  
      
        curr = *blocks;  
      
        /* Found a best-fit block! LOL */  
    #ifdef DEBUG  
        if ((*blocks = word_to_ptr(NEXT_SAMESZ_BLKP(curr))) == NULL)  
        {  
            printf("** All blocks with size %u (request: %zu) deleted.\n", GET_SIZE(HDRP(curr)), asize);  
        }  
    #else  
        /* Set the node to the next same size block if it has */  
        *blocks = word_to_ptr(NEXT_SAMESZ_BLKP(curr));  
    #endif  
        remove_freed_block(curr);  
        return curr;  
    }  
      
    /* 
     * printblock - print a block for debugging 
     */  
    static inline void printblock(block_ptr bp)  
    {  
        size_t hsize, halloc, fsize, falloc;  
      
        hsize = GET_SIZE(HDRP(bp));  
        halloc = GET_ALLOC(HDRP(bp));  
        fsize = GET_SIZE(FTRP(bp));  
        falloc = GET_ALLOC(FTRP(bp));  
      
        if (hsize == 0)  
        {  
            printf("%p: EOL\n", bp);  
            return;  
        }  
        if (halloc)  
            printf("\033[43;37m%p: header: [%zu:%c:%c] footer: -\033[0m\n", bp,  
            hsize, (GET_PREV_ALLOC(bp) ? 'a' : 'f'), (halloc ? 'a' : 'f'));  
        else  
        {  
            printf("\033[42;30m%p: header: [%zu:%c:%c] footer: [%zu:%c]\033[0m", bp,  
                hsize, (GET_PREV_ALLOC(bp) ? 'a' : 'f'), (halloc ? 'a' : 'f'),  
                fsize, (falloc ? 'a' : 'f'));  
            if (IS_BST_NODE(bp))  
                printf("\033[1;44;33m[BST Node| parent slotp: %p, l: %p, r: %p]\033[0m",  
                PARENT_CHLDSLOTP(bp), LCHLD_BLKP(bp), RCHLD_BLKP(bp));  
            if (PREV_SAMESZ_BLKP(bp))  
                printf("\033[1;33m[PREV] %p\033[0m", word_to_ptr(PREV_SAMESZ_BLKP(bp)));  
            putchar('\n');  
        }  
    }  
      
    /* 
     * checkblock - as the name goes 
     */  
    static inline void checkblock(block_ptr bp)  
    {  
        if (!aligned(bp))  
            printf("\n\033[1;47;31m## Error: %p is not doubleword aligned\033[0m\n", bp);  
        if (!GET_ALLOC(HDRP(bp)) && (GET(HDRP(bp)) & ~0x2) != (GET(FTRP(bp)) & ~0x2))  
            printf("\n\033[1;47;31m## Error: header does not match footer, header: %u, footer: %u \033[0m\n",  
            GET(HDRP(bp)), GET(FTRP(bp)));  
        if (GET_ALLOC(HDRP(bp)) != (GET_PREV_ALLOC(NEXT_BLKP(bp)) >> 1))  
            printf("\n\033[1;47;31m## Error: %p allocation does not match next block's prev_alloc\033[0m\n", bp);  
    }  
      
    static void printchain(block_ptr node)  
    {  
        while (node)  
        {  
            printblock(node);  
            printf("->");  
            node = word_to_ptr(NEXT_SAMESZ_BLKP(node));  
        }  
    }  
      
    static void printtree(block_ptr node, int depth)  
    {  
        int i;  
        if (node == NULL)  
            return;  
        printf("BST: ");  
        for (i = 0; i < depth; i++)  
            putchar('-');  
        printchain(node);  
        putchar('\n');  
        printtree(LCHLD_BLKP(node), depth + 1);  
        printtree(RCHLD_BLKP(node), depth + 1);  
    }  
      
    static void checklist(block_ptr node)  
    {  
        if (node == NULL)  
            return;  
        if (PREV_SAMESZ_BLKP(node) &&  
            word_to_ptr(NEXT_SAMESZ_BLKP(word_to_ptr(PREV_SAMESZ_BLKP(node)))) != node)  
            printf("\n\033[1;47;31m## Bad neighbor pointer: %p\033[0m\n", node);  
        checklist(word_to_ptr(NEXT_SAMESZ_BLKP(node)));  
    }  
      
    static void checktree(block_ptr node)  
    {  
        if (node == NULL)  
            return;  
        if (*PARENT_CHLDSLOTP(node) != node)  
            printf("\n\033[1;47;31m## Bad parent pointer: %p\033[0m\n", node);  
        checklist(node);  
        checktree(LCHLD_BLKP(node));  
        checktree(RCHLD_BLKP(node));  
    }  
      
    /* 
     * checkheap - check the heap for consistency 
     */  
    void mm_checkheap(int verbose)  
    {  
        char *bp = heap_listp;  
      
        if (verbose)  
            printf("Heap (%p):\n", heap_listp);  
      
        if ((GET_SIZE(HDRP(heap_listp)) != DSIZE) || !GET_ALLOC(HDRP(heap_listp)))  
            printf("\n\033[1;47;31m## Bad prologue header\033[0m\n");  
        checkblock(heap_listp);  
      
        for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp))  
        {  
            if (verbose)  
                printblock(bp);  
            checkblock(bp);  
        }  
      
        if (verbose)  
        {  
            printblock(bp);  
            {  
                unsigned int i;  
                for (i = 1; i <= fixed_bin_count; i++)  
                if (bins[i - 1])  
                {  
                    printf("BIN #%d: size = %d ", i, i * DSIZE);  
                    checklist(bins[i - 1]);  
                    printchain(bins[i - 1]);  
                }  
                putchar('\n');  
                checktree(larger_bin_root);  
                printtree(larger_bin_root, 0);  
            }  
        }  
        if ((GET_SIZE(HDRP(bp)) != 0) || !(GET_ALLOC(HDRP(bp))))  
            printf("\n\033[1;47;31m## Bad epilogue header\033[0m\n");  
    } 

    最终成绩如图:

Introduction The usual implementation of malloc and free are unforgiving to errors in their callers' code, including cases where the programmer overflows an array, forgets to free memory, or frees a memory block twice. This often does not affect the program immediately, waiting until the corrupted memory is used later (in the case of overwrites) or gradually accumulating allocated but unused blocks. Thus, debugging can be extremely difficult. In this assignment, you will write a wrapper for the malloc package that will catch errors in the code that calls malloc and free. The skills you will have learned upon the completion of this exercise are pointer arithmetic and a greater understanding of the consequences of subtle memory mistakes. Logistics Unzip debugging_malloc.zip into an empty directory. The files contained are as follows: File(s): Function: debugmalloc.c Contains the implementation of the three functions you will be writing. This is the one file you will be editing and handing in. debugmalloc.h Contains the declaration of the functions, as well as the macros that will call them. driver.c Contains main procedure and the code that will be calling the functions in the malloc package dmhelper.c, dmhelper.h Contain the helper functions and macros that you will be calling from your code grader.pl Perl script that runs your code for the various test cases and gives you feedback based on your current code debugmalloc.dsp Exercise 3 project file debugmalloc.dsw Exercise 3 workspace file tailor.h, getopt.c, getopt.h Tools that are used only by the driver program for I/O purposes. You will not need to know what the code in these files do. Others Required by Visual C++. You do not need to understand their purpose Specification Programs that use this package will call the macros MALLOC and FREE. MALLOC and FREE are used exactly the same way as the malloc() and free() functions in the standard C malloc package. That is, the line void *ptr = MALLOC ( n ) ;will allocate a payload of at least n bytes, and ptr will point to the front of this block. The line FREE(ptr);will cause the payload pointed to by ptr to be deallocated and become available for later use. The macros are defined as follows: #define MALLOC(s) MyMalloc(s, __FILE__, __LINE__) #define FREE(p) MyFree(p, __FILE__, __LINE__) The __FILE__ macro resolves to the filename and __LINE__ resolves to the current line number. The debugmalloc.c file contains three functions that you are required to implement, as shown: void *MyMalloc(size_t size, char *filename, int linenumber); void MyFree(void *ptr, char *filename, int linenumber); int AllocatedSize(); Using the macros above allow MyMalloc and MyFree to be called with the filename and line number of the actual MALLOC and FREE calls, while retaining the same form as the usual malloc package. By default, MyMalloc and MyFree() simply call malloc() and free(), respectively, and return immediately. AllocatedSize() should return the number of bytes currently allocated by the user: the sum of the requested bytes through MALLOC minus the bytes freed using FREE. By default, it simply returns 0 and thus is unimplemented. The definitions are shown below: void *MyMalloc(size_t size, char *filename, int linenumber) { return (malloc(size)); } void MyFree(void *ptr, char *filename, int linenumber) { free(ptr); } int AllocatedSize() { return 0; } Your job is to modify these functions so that they will catch a number of errors that will be described in the next section. There are also two optional functions in the debugmalloc.c file that you can implement: void PrintAllocatedBlocks(); int HeapCheck(); PrintAllocatedBlocks should print out information about all currently allocated blocks. HeapCheck should check all the blocks for possible memory overwrites. Implementation Details To catch the errors, you will allocate a slightly larger amount of space and insert a header and a footer around the "requested payload". MyMalloc() will insert information into this area, and MyFree() will check to see if the information has not changed. The organization of the complete memory block is as shown below: Header Checksum ... Fence Payload Footer Fence Note:MyMalloc() returns a pointer to the payload, not the beginning of the whole block. Also, the ptr parameter passed into MyFree(void *ptr) will point to the payload, not the beginning of the block. Information that you might want to store in this extra (header, footer) area include: a "fence" immediately around the requested payload with a known value like 0xCCDEADCC, so that you can check if it has been changed when the block is freed. the size of the block a checksum for the header to ensure that it has not been corrupted (A checksum of a sequence of bits is calculated by counting the number of "1" bits in the stream. For example, the checksum for "1000100010001000" is 4. It is a simple error detection mechanism.) the filename and line number of the MALLOC() call The errors that can occur are: Error #1: Writing past the beginning of the user's block (through the fence) Error #2: Writing past the end of the user's block (through the fence) Error #3: Corrupting the header information Error #4: Attempting to free an unallocated or already-freed block Error #5: Memory leak detection (user can use ALLOCATEDSIZE to check for leaks at the end of the program) To report the first four errors, call one of these two functions: void error(int errorcode, char *filename, int linenumber); errorcode is the number assigned to the error as stated above. filename and linenumber contain the filename and line number of the line (the free call) in which the error is invoked. For example, call error(2, filename, linenumber) if you come across a situation where the footer fence has been changed. void errorfl(int errorcode, char *filename_malloc, int linenumber_malloc, char *filename_free, int linenumber_free); This is the same as the error(), except there are two sets of filenames and line numbers, one for the statement in which the block was malloc'd, and the other for the statement in which the block was free'd (and the error was invoked). The fact that MyMalloc() and MyFree() are given the filename and line number of the MALLOC() and FREE() call can prove to be very useful when you are reporting errors. The more information you print out, the easier it will be for the programmer to locate the error. Use errorfl() instead of error() whenever possible. errorfl() obviously cannot be used on situations where FREE() is called on an unallocated block, since it was not ever MALLOC'd. Note: You will only be reporting errors from MyFree(). None of the errors can be caught in MyMalloc() In the case of memory leaks, the driver program will call AllocatedSize(), and the grader will look at its return value and possible output. AllocatedSize() should return the number of bytes currently allocated from MALLOC and FREE calls. For example, the code segment: void *ptr1 = MALLOC(10), *ptr2 = MALLOC(8); FREE(ptr2); printf("%d\n", AllocatedSize()); should print out "10". Once you have gotten to the point where you can catch all of the errors, you can go an optional step further and create a global list of allocated blocks. This will allow you to perform analysis of memory leaks and currently allocated memory. You can implement the void PrintAllocatedBlocks() function, which prints out the filename and line number where all currently allocated blocks were MALLOC()'d. A macro is provided for you to use to print out information about a single block in a readable and gradeable format: PRINTBLOCK(int size, char *filename, int linenumber) Also, you can implement the int HeapCheck() function. This should check all of the currently allocated blocks and return -1 if there is an error and 0 if all blocks are valid. In addition, it should print out the information about all of the corrupted blocks, using the macro #define PRINTERROR(int errorcode, char *filename, int linenumber), with errorcode equal to the error number (according to the list described earlier) the block has gone through. You may find that this global list can also allow you to be more specific in your error messages, as it is otherwise difficult to determine the difference between an overwrite of a non-payload area and an attempted FREE() of an unallocated block. Evaluation You are given 7 test cases to work with, plus 1 extra for testing a global list. You can type "debugmalloc -t n" to run the n-th test. You can see the code that is being run in driver.c. If you have Perl installed on your machine, use grader.pl to run all the tests and print out a table of results. There are a total of 100 possible points. Here is a rundown of the test cases and desired output (do not worry about the path of the filename): Test case #1 Code char *str = (char *) MALLOC(12); strcpy(str, "123456789"); FREE(str); printf("Size: %d\n", AllocatedSize()); PrintAllocatedBlocks(); Error # None Correct Output Size: 0 Points worth 10 Details 10 points for not reporting an error and returning 0 in AllocatedSize() Test case #2 Code char *str = (char *) MALLOC(8); strcpy(str, "12345678"); FREE(str); Error # 2 Correct Output Error: Ending edge of the payload has been overwritten. in block allocated at driver.c, line 21 and freed at driver.c, line 23 Points worth 15 Details 6 pts for catching error 3 pts for printing the filename/line numbers 6 pts for correct error message Test case #3 Code char *str = (char *) MALLOC(2); strcpy(str, "12"); FREE(str); Error # 2 Correct Output Error: Ending edge of the payload has been overwritten. in block allocated at driver.c, line 28 and freed at driver.c, line 30 Points worth 15 Details 6 pts for catching error 3 pts for printing the filename/line numbers 6 pts for correct error message Test case #4 Code void *ptr = MALLOC(4); *ptr2 = MALLOC(6); FREE(ptr); printf("Size: %d\n", AllocatedSize()); PrintAllocatedBlocks(); Error # None Correct Output Size: 6 Currently allocated blocks: 6 bytes, created at driver.c, line 34 Points worth 15 Details 15 pts for not reporting an error and returning 6 from AllocatedSize Extra for printing out the extra block Test case #5 Code void *ptr = MALLOC(4); FREE(ptr); FREE(ptr); Error # 4 Correct Output Error: Attempting to free an unallocated block. in block freed at driver.c, line 43 Points worth 15 Details 15 pts for catching error Extra for correct error message Test case #6 Code char *ptr = (char *) MALLOC(4); *((int *) (ptr - 8)) = 8 + (1 << 31); FREE(ptr); Error # 1 or 3 Correct Output Error: Header has been corrupted.or Error: Starting edge of the payload has been overwritten. in block allocated at driver.c, line 47 and freed at driver.c, line 49 Points worth 15 Details 9 pts for catching error 6 pts for a correct error message Test case #7 Code char ptr[5]; FREE(ptr); Error # 4 Correct Output Error: Attempting to free an unallocated block. in block freed at driver.c, line 54 Points worth 15 Details 15 pts for recognizing error Extra for printing correct error message Test case #8 (Optional) Code int i; int *intptr = (int *) MALLOC(6); char *str = (char *) MALLOC(12); for(i = 0; i < 6; i++) { intptr[i] = i; } if (HeapCheck() == -1) { printf("\nCaught Errors\n"); } Error # None Correct Output Error: Ending edge of the payload has been overwritten. Invalid block created at driver.c, line 59 Caught Errors Points worth Extra Details "Caught Errors" indicates that the HeapCheck() function worked correctly. Extra points possible. Your instructor may give you extra credit for implementing a global list and the PrintAllocatedBlocks() and HeapCheck() functions.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值