void free_random() { void *heap0 = get_heap_base(); Free_Header *freelist0 = get_heap_freelist(); free(buf); // try to free a valid but non-heap data address void *heap1 = get_heap_base(); Free_Header *freelist1 = get_heap_freelist(); assert_addr_equal(heap1, heap0); assert_addr_equal(freelist1, freelist0); }
void malloc_large_size_then_free() { Free_Header *freelist = get_heap_freelist();//free list before malloc void *p = malloc(2048); assert_addr_not_equal(p, NULL); assert_equal(chunksize(p), request2size(2048)); Free_Header *freelist1 = get_heap_freelist(); // free list after malloc Busy_Header *heap = get_heap_base(); assert_addr_equal(p,heap); assert_addr_not_equal(heap,freelist1); free(p); Busy_Header *heap1 = get_heap_base(); Free_Header *freelist2 = get_heap_freelist(); // free list after free,should back to status before malloc assert_addr_equal(freelist,freelist2); assert_addr_equal(heap1,freelist2); }
void long_freelist() { Busy_Header* b[20]; for(int i = 0; i < 20; i++){ b[i] = malloc(i); assert_addr_equal(get_freelist(), find_next(b[i])); assert_addr_equal(get_freelist()->prev, NULL); } Free_Header *freelist0 = get_freelist(); for( int i = 0; i <20 ; i++){ free(b[i]); assert_addr_equal(get_freelist(), b[i]); if (i+1 < 20) assert_addr_equal(find_next(get_freelist()), b[i+1]); assert_addr_equal(get_freelist()->prev, NULL); } //last free causes a merge Heap_Info info = verify_heap(); assert_equal(info.busy, 0); assert_equal(info.free, 20); assert_equal(info.busy_size + info.free_size, get_heap_info().heap_size); // out of heap assert_addr_equal(get_freelist(), b[19]); assert_addr_equal(find_next(get_freelist()), get_heap_base() + info.heap_size); //out of heap assert_addr_equal(((Free_Header *)b[0])->next, NULL); //end }
//free the first chunk, then free last chunk to merge with the end of free list void merge_with_end() { three_malloc(); Busy_Header *b_1 = get_heap_base(); Busy_Header *b_2 = find_next(b_1); Busy_Header *b_3 = find_next(b_2); free(b_1); //free the first chunk Free_Header *freelist0 = get_freelist(); //get the new freelist assert_addr_equal(freelist0, b_1); assert_addr_equal(freelist0->next, find_next(b_3)); free(b_3); //free the last chunk, merge Free_Header *freelist1 = get_freelist(); assert_addr_equal(freelist1, b_3); assert_addr_equal(freelist1->next, b_1); assert_addr_equal(freelist1->prev, NULL); assert_addr_equal(freelist1->next->prev, freelist1); assert_addr_equal(freelist1->next->next, NULL); Heap_Info info = verify_heap(); assert_equal(info.busy, 1); assert_equal(info.free, 2); assert_equal(info.free_size, HEAP_SIZE - info.busy_size); assert_equal(freelist1->next->size, b_1->size); assert_equal(find_next(find_next(b_1)), freelist1); }
//five consecutive chunks allocated void five_malloc() { void *p = get_heap_base(); Busy_Header *b_1 = malloc(100); assert_addr_equal(b_1, p); //b_1 is at the start of heap assert_equal(chunksize(b_1), request2size(100)); Busy_Header *b_2 = malloc(200); Busy_Header *b1_next = find_next(b_1); assert_addr_equal(b1_next,b_2); //b_2 is after b_1 assert_equal(chunksize(b_2), request2size(200)); Busy_Header *b_3 = malloc(300); Busy_Header *b2_next = find_next(b_2); assert_addr_equal(find_next(b_2),b_3); //b_3 is after b_2 assert_equal(chunksize(b_3), request2size(300)); Busy_Header *b_4 = malloc(400); Busy_Header *b3_next = find_next(b_3); assert_addr_equal(find_next(b_3),b_4); //b_4 is after b_3 assert_equal(chunksize(b_4), request2size(400)); Busy_Header *b_5 = malloc(500); Busy_Header *b4_next = find_next(b_4); assert_addr_equal(find_next(b_4),b_5); //b_5 is after b_4 assert_equal(chunksize(b_5), request2size(500)); Heap_Info info = verify_heap(); assert_equal(info.busy, 5); assert_equal(info.free, 1); assert_equal(info.free_size, HEAP_SIZE - info.busy_size); }
//free the middle chunk, than the first chunk, leading to a merge with the head of the list void merge_with_head() { free_without_merging(); //free middle chunk first void *p = get_heap_base(); // the first allocated chunk on the heap Free_Header *freelist0 = get_freelist(); //get the head of freelist, which is the middle chunk assert_addr_not_equal(freelist0, p); Free_Header *next = freelist0->next; free(p); //free the chunk before head of the free list, need to merge Free_Header *freelist1 = get_freelist(); //get the new freelist assert_addr_equal(freelist1, p); // new head is at the base of heap assert_addr_not_equal(freelist1, freelist0); assert_addr_not_equal(freelist1->next, freelist0); assert_addr_equal(freelist1->next, next); assert_addr_equal(freelist1->prev, NULL); assert_addr_equal(next->next, NULL); assert_addr_equal(next->prev, freelist1); Heap_Info info = verify_heap(); assert_equal(info.busy, 1); assert_equal(info.free, 2); assert_equal(info.free_size, HEAP_SIZE - info.busy_size); assert_equal(freelist1->next->size, info.free_size-freelist1->size); assert_equal(find_next(find_next(freelist1)), freelist1->next); }
/* * for each free request * if chunk size over 1024, free it and add to free list (sorted) * other wise add to bin[chunk_size-1] */ void free(void *p) { if (p == NULL) return; void *start_of_heap = get_heap_base(); void *end_of_heap = start_of_heap + DEFAULT_MAX_HEAP_SIZE - 1; // last valid address of heap if ( p<start_of_heap || p>end_of_heap ) { #ifdef DEBUG fprintf(stderr, "free of non-heap address %p\n", p); #endif return; } Free_Header *q = (Free_Header *) p; if ( !(q->size & BUSY_BIT) ) { // stale pointer? If already free'd better not try to free it again #ifdef DEBUG fprintf(stderr, "free of stale pointer %p\n", p); #endif return; } q->size &= SIZEMASK; if (q->size<= BIN_SIZE) { q->next = bin[q->size-1]; bin[q->size-1] = q; } else { q->next = freelist; freelist = q; } }
void bin_malloc_free_malloc() { // test bin malloc and free void *p = malloc(99); // should split heap into two chunks assert_addr_not_equal(p, NULL); Free_Header *freelist = get_heap_freelist(); Busy_Header *heap = get_heap_base(); assert_addr_not_equal(freelist, heap); // check 1st chunk assert_equal(p, heap); assert_equal(chunksize(p), request2size(99)); // check 2nd chunk assert_equal(freelist->size, HEAP_SIZE-request2size(99)); assert_addr_equal(freelist->next, NULL); Free_Header *freelist1 = get_bin_freelist(99);// freelist of bin should be NULL free(p); // free to bin Free_Header *freelist2 = get_bin_freelist(99);// freelist of bin should be have one element p assert_addr_not_equal(freelist1,freelist2); void *p1 = malloc(99); // this malloc should be from bin assert_addr_not_equal(p1, NULL); Free_Header *freelist3 = get_bin_freelist(99); // freelist of bin should be NULL assert_addr_equal(freelist3,NULL); free(p1); Free_Header *freelist4 = get_bin_freelist(99); // freelist should have one element p1 assert_addr_equal(freelist2,freelist4); }
void malloc_then_free() { one_malloc(); void *p = get_heap_base(); // should be allocated chunk Free_Header *freelist0 = get_freelist(); free(p); Free_Header *freelist1 = get_freelist(); // allocated chunk is freed and becomes head of new freelist assert_addr_equal(freelist1, p); assert_addr_equal(freelist1, get_heap_base()); assert_addr_not_equal(freelist0, freelist1); assert_equal(chunksize(freelist1) + chunksize(freelist1->next), HEAP_SIZE); Heap_Info info = verify_heap(); assert_equal(info.busy, 0); assert_equal(info.busy_size, 0); assert_equal(info.free, 1); // 1 free chunk after merging assert_equal(info.free_size, HEAP_SIZE); }
void two_malloc() { one_malloc(); void *p0 = get_heap_base(); Free_Header *freelist0 = get_heap_freelist(); Busy_Header *p = malloc(200); assert_addr_not_equal(p, NULL); // check 2nd alloc chunk assert_equal(p, freelist0); // should return previous free chunk assert_equal(chunksize(p), request2size(200)); // check remaining free chunk Free_Header *freelist1 = get_heap_freelist(); assert_addr_not_equal(freelist0, freelist1); assert_addr_not_equal(freelist0, get_heap_base()); assert_equal(chunksize(freelist1), HEAP_SIZE-request2size(100)-request2size(200)); assert_equal(chunksize(p0)+chunksize(p)+chunksize(freelist1), HEAP_SIZE); assert_addr_equal(freelist1->next, NULL); Heap_Info info = verify_heap(); assert_equal(info.busy, 2); assert_equal(info.busy_size, request2size(100) + request2size(200)); assert_equal(info.free, 1); assert_equal(info.free_size, HEAP_SIZE - request2size(100) - request2size(200)); }
void one_malloc() { void *p = malloc(100); assert_addr_not_equal(p, NULL); Free_Header *freelist = get_heap_freelist(); Busy_Header *heap = get_heap_base(); assert_addr_not_equal(freelist, heap); // check 1st chunk assert_equal(p, heap); assert_equal(chunksize(p), request2size(100)); // check 2nd chunk assert_equal(freelist->size, HEAP_SIZE-request2size(100)); assert_addr_equal(freelist->next, NULL); Heap_Info info = verify_heap(); assert_equal(info.busy, 1); assert_equal(info.busy_size, request2size(100)); assert_equal(info.free, 1); assert_equal(info.free_size, HEAP_SIZE - request2size(100)); }
//allocate 10 consecutive chunks, free from the back to the front //should fuse the heap to one free chunk void fuse_to_one() { Busy_Header* b[10]; for(int i = 0; i < 10; i++){ b[i] = malloc(100); assert_addr_equal(get_freelist(), find_next(b[i])); assert_addr_equal(get_freelist()->prev, NULL); } Free_Header *freelist0 = get_freelist(); for( int i = 9; i >= 0 ; i--){ free(b[i]); assert_addr_equal(get_freelist(), b[i]); assert_addr_equal(get_freelist()->prev, NULL); } Heap_Info info = verify_heap(); assert_equal(info.busy, 0); assert_equal(info.free, 1); assert_equal(info.busy_size + info.free_size, get_heap_info().heap_size); assert_addr_equal(find_next(get_freelist()), get_heap_base() + info.heap_size); assert_addr_equal(freelist0->next, NULL); }
//free the first chunk, then free last chunk to merge with the end of free list void merge_with_middle() { five_malloc(); Busy_Header *b_1 = get_heap_base(); Busy_Header *b_2 = find_next(b_1); Busy_Header *b_3 = find_next(b_2); Busy_Header *b_4 = find_next(b_3); Busy_Header *b_5 = find_next(b_4); size_t size_3 = b_3->size & SIZEMASK; size_t size_4 = b_4->size & SIZEMASK; free(b_4); free(b_2); Free_Header *freelist0 = get_freelist(); //get the new freelist at b_2->b_4->after b_5 Free_Header *last = find_next(b_5); assert_addr_equal(freelist0, b_2); assert_addr_equal(freelist0->next, b_4); assert_addr_equal(freelist0->prev, NULL); assert_addr_equal(((Free_Header*)b_4) ->next, last); assert_addr_equal(((Free_Header*)b_4) ->prev, b_2); assert_addr_equal(last->next, NULL); assert_addr_equal(last->prev, b_4); free(b_3); //merge with b_4 Free_Header *freelist1 = get_freelist(); //get new free list at b_3; assert_addr_equal(freelist1, b_3); assert_equal(freelist1->size & SIZEMASK, size_3 + size_4); assert_addr_equal(freelist1->next, b_2); //freelist1 ->freelist0->last assert_addr_equal(freelist1->prev, NULL); assert_addr_equal(freelist0->next, last); assert_addr_equal(freelist0->prev, freelist1); assert_addr_equal(last->next, NULL); assert_addr_equal(last->prev, freelist0); Heap_Info info = verify_heap(); assert_equal(info.busy, 2); assert_equal(info.free, 3); assert_equal(info.free_size, HEAP_SIZE - info.busy_size); assert_equal(freelist1->next->size + freelist0->next->size, info.free_size-freelist1->size); }
/* Free chunk p by adding to head of free list */ void free(void *p) { if (p == NULL) return; void *start_of_heap = get_heap_base(); void *end_of_heap = start_of_heap + heap_size - 1; // last valid address of heap if ( p<start_of_heap || p>end_of_heap ) { #ifdef DEBUG fprintf(stderr, "free of non-heap address %p\n", p); #endif return; } Free_Header *q = (Free_Header *) p; if ( !(q->size & BUSY_BIT) ) { // stale pointer? If already free'd better not try to free it again #ifdef DEBUG fprintf(stderr, "free of stale pointer %p\n", p); #endif return; } q->next = freelist; q->size &= SIZEMASK; // turn off busy bit freelist = q; }
/* Walk heap jumping by size field of chunk header. Return an info record. */ Heap_Info get_heap_info() { void *heap = get_heap_base(); // should be allocated chunk void *end_of_heap = heap + heap_size - 1; // last valid address of heap Busy_Header *p = heap; uint32_t busy = 0; uint32_t free = 0; uint32_t busy_size = 0; uint32_t free_size = 0; while ( (void*)p>=heap && (void*)p<=end_of_heap ) { // stay inbounds, walking heap // track if ( p->size & BUSY_BIT ) { busy++; busy_size += chunksize(p); } else { free++; free_size += chunksize(p); } p = (Busy_Header *)((char *) p + chunksize(p)); } return (Heap_Info){heap_size, busy, busy_size, free, free_size}; }
Heap_Info get_heap_info() { void *heap = get_heap_base(); void *end_of_heap = heap + DEFAULT_MAX_HEAP_SIZE - 1; Busy_Header *p = heap; uint32_t busy = 0; uint32_t free = 0; uint32_t busy_size = 0; uint32_t free_size = 0; while ( p >= heap && p <= end_of_heap ) { if ( p->size & BUSY_BIT ) { busy++; busy_size += chunksize(p); } else { free++; free_size += chunksize(p); } p = (Busy_Header *)((char *) p + chunksize(p)); } return (Heap_Info) { DEFAULT_MAX_HEAP_SIZE, busy, busy_size, free, free_size }; }
//free the chunk in the middle of three busy chunks void free_without_merging() { three_malloc(); Busy_Header *b_1 = get_heap_base(); Busy_Header *b_2 = find_next(b_1); Busy_Header *b_3 = find_next(b_2); Free_Header *freelist0 = get_freelist(); //get the head of freelist, which is at the end of allocated chunks assert_addr_equal(freelist0, find_next(b_3)); free(b_2); //free the chunk in the middle, which becomes the head of the new freelist Free_Header *freelist1 = get_freelist(); //get the new freelist assert_addr_not_equal(freelist1, b_1); assert_addr_not_equal(freelist0, freelist1); assert_addr_equal(freelist1, b_2); assert_addr_equal(freelist1->next, freelist0); //two free chunks in the list assert_equal(chunksize(b_1) + chunksize(b_2) + chunksize(b_3) + chunksize(freelist0), HEAP_SIZE); assert_equal(chunksize(b_1) + chunksize(b_3) + chunksize(freelist1) + chunksize(freelist0), HEAP_SIZE); Heap_Info info = verify_heap(); assert_equal(info.busy, 2); assert_equal(info.busy_size, chunksize(b_1) + chunksize(b_3)); assert_equal(info.free, 2); // 2 free chunks not next to each other assert_equal(info.free_size, chunksize(freelist1) + chunksize(freelist1->next)); }
void test_init_shutdown() { freelist_init(HEAP_SIZE); assert_addr_equal(get_freelist(), get_heap_base()); freelist_shutdown(); }
//split chunk void split_chunk(){ printf("after allocation:\n"); Busy_Header* b[4]; for(int i = 0; i < 4; i++){ b[i] = malloc(450); printf("b[%d]: %p\n", i, b[i]); } assert_equal(b[0]->size & SIZEMASK, request2size(450)); assert_equal(b[1]->size & SIZEMASK, request2size(450)); assert_equal(b[2]->size & SIZEMASK, request2size(450)); assert_equal(b[3]->size & SIZEMASK, request2size(450)); Free_Header* f4 = find_next(b[3]); printf("head: %p\n", f4); Heap_Info info = verify_heap(); assert_equal(info.busy, 4); assert_equal(info.free, 1); assert_equal(info.busy_size, 1824); assert_equal(info.free_size, 176); assert_addr_equal(get_freelist(), f4); assert_addr_equal(get_freelist()->next, NULL); assert_addr_equal(get_freelist()->prev, NULL); free(b[2]); info = verify_heap(); assert_equal(info.busy, 3); assert_equal(info.free, 2); assert_equal(info.busy_size, 1368); assert_equal(info.free_size, 632); assert_addr_equal(get_freelist(), b[2]); assert_addr_equal(get_freelist()->next, f4); assert_addr_equal(get_freelist()->next->next, NULL); assert_addr_equal(f4->prev, b[2]); assert_addr_equal(f4->prev->prev, NULL); printf("after free b[2]\n"); Free_Header *head = get_freelist(); print_both_ways(head); free(b[0]); info = verify_heap(); assert_equal(info.busy, 2); assert_equal(info.free, 3); assert_equal(info.busy_size, 912); assert_equal(info.free_size, 1088); assert_addr_equal(get_freelist(), b[0]); assert_addr_equal(get_freelist()->next, b[2]); assert_addr_equal(get_freelist()->next->next, f4); assert_addr_equal(get_freelist()->next->next->next, NULL); assert_addr_equal(f4->prev, b[2]); assert_addr_equal(f4->prev->prev, b[0]); assert_addr_equal(f4->prev->prev->prev, NULL); printf("after free b[0]\n"); head = get_freelist(); print_both_ways(head); Busy_Header *split = malloc(200); printf("after malloc(200)\n"); head = get_freelist(); print_both_ways(head); assert_addr_equal(split, get_heap_base()); Free_Header *newhead = get_freelist(); assert_addr_equal(find_next(split),newhead); assert_addr_equal(get_freelist(), find_next(split)); assert_addr_equal(get_freelist()->next, b[2]); assert_addr_equal(get_freelist()->next->next, f4); assert_addr_equal(get_freelist()->next->next->next, NULL); assert_addr_equal(f4->prev, b[2]); assert_addr_equal(f4->prev->prev, newhead); assert_addr_equal(f4->prev->prev->prev, NULL); info = verify_heap(); assert_equal(info.busy, 3); assert_equal(info.free, 3); assert_equal(info.busy_size + info.free_size, get_heap_info().heap_size); // out of heap*/ }