int main(int argc, char *argv[]) { // printf("sizeof(Busy_Header) == %zu\n", sizeof(Busy_Header)); // printf("sizeof(Free_Header) == %zu\n", sizeof(Free_Header)); for (int i=0; i<=MINSIZE-sizeof(Busy_Header); i++) { // fprintf(stderr, "request2size(%d) == %lu\n", i, request2size((size_t)i)); assert(request2size((size_t) i) == MINSIZE ); } if ( MINSIZE==16 ) { static const int N = 9; static const size_t sizes[2*N] = { // (request, adjusted size) pairs 13, 24, 14, 24, 15, 24, 16, 24, 17, 24, 18, 24, 19, 24, 20, 24, 21, 32, }; for (int i=0; i < 2*N; i += 2) { // fprintf(stderr, "request2size(%zu) == %lu\n", sizes[i], request2size(sizes[i])); assert(request2size(sizes[i]) == sizes[i+1]); } } }
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); }
//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); }
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)); }
//skip first free chunk, which is not big enough void search_along_list() { 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); //after malloc, free b3, b0 free(b[3]); free(b[0]); Busy_Header *skip = malloc(600); printf("after malloc(600)\n"); Free_Header *head = get_freelist(); print_both_ways(head); info = verify_heap(); assert_equal(info.busy, 3); assert_equal(info.free, 2); assert_equal(info.busy_size + info.free_size, get_heap_info().heap_size); }
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* realloc(void* mem, size_t bytes) { if (mem == 0) return malloc(bytes); else { size_t nb = request2size(bytes); mchunkptr p = mem2chunk(mem); size_t oldsize = p->size; int room; mchunkptr nxt; UPDATE_STATS((++n_reallocs, requested_mem += bytes-oldsize)); /* try to expand (even if already big enough), to clean up chunk */ while (!inuse(nxt = next_chunk(p))) { UPDATE_STATS ((malloced_mem += nxt->size, ++n_consol)); unlink(nxt); set_size(p, p->size + nxt->size); } room = p->size - nb; if (room >= 0) { split(p, nb); UPDATE_STATS(malloced_mem -= room); return chunk2mem(p); } else /* do the obvious */ { void* newmem; set_inuse(p); /* don't let malloc consolidate us yet! */ newmem = malloc(nb); bcopy(mem, newmem, oldsize - SIZE_SZ); free(mem); UPDATE_STATS(++n_reallocs_with_copy); return newmem; } } }
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* malloc(size_t bytes) { size_t nb = request2size(bytes); /* padded request size */ mbinptr b = size2bin(nb); /* corresponding bin */ mchunkptr hd = &(b->hd); /* head of its list */ mchunkptr p = hd->fd; /* chunk traverser */ UPDATE_STATS((requested_mem+=bytes, ++n_malloc_bins)); /* Try a (near) exact match in own bin */ /* clean out unusable but consolidatable chunks in bin while traversing */ while (p != hd) { UPDATE_STATS(++n_malloc_chunks); if (p->size >= nb) goto found; else /* try to consolidate; same code as malloc_find_space */ { mchunkptr nextp = p->fd; /* save, in case of relinks */ int consolidated = 0; /* only unlink/relink if consolidated */ mchunkptr t; while (!inuse(t = prev_chunk(p))) /* consolidate backward */ { if (!consolidated) { consolidated = 1; unlink(p); } if (t == nextp) nextp = t->fd; unlink(t); set_size(t, t->size + p->size); p = t; UPDATE_STATS (++n_consol); } while (!inuse(t = next_chunk(p))) /* consolidate forward */ { if (!consolidated) { consolidated = 1; unlink(p); } if (t == nextp) nextp = t->fd; unlink(t); set_size(p, p->size + t->size); UPDATE_STATS (++n_consol); } if (consolidated) { if (p->size >= nb) { /* make it safe to unlink again below */ UPDATE_STATS(++n_avail); p->fd = p->bk = p; goto found; } else consollink(p); } p = nextp; } } b->dirty = 0; /* true if got here */ /* Scan bigger bins for a victim */ while (++b <= malloc_maxbin) { UPDATE_STATS(++n_malloc_bins); if ((p = b->hd.bk) != &(b->hd)) /* no need to check size */ goto found; } /* Consolidate or sbrk */ p = malloc_find_space(nb); if (p == 0) return 0; /* allocation failure */ found: /* Use what we found */ unlink(p); split(p, nb); UPDATE_STATS(do_malloc_stats(p)); return chunk2mem(p); }
void* memalign(size_t alignment, size_t bytes) { mchunkptr p; size_t nb = request2size(bytes); /* find an alignment that both we and the user can live with: */ /* least common multiple guarantees mutual happiness */ size_t align = lcm(alignment, MALLOC_MIN_OVERHEAD); size_t mask = align - 1; /* call malloc with worst case padding to hit alignment; */ /* we will give back extra */ size_t req = nb + align + MINSIZE; void* m = malloc(req); if (m == 0) return m; p = mem2chunk(m); /* keep statistics on track */ UPDATE_STATS(--n_mallocs); UPDATE_STATS(malloced_mem -= p->size); UPDATE_STATS(requested_mem -= req); UPDATE_STATS(requested_mem += bytes); if (((int)(m) & (mask)) != 0) /* misaligned */ { /* find an aligned spot inside chunk */ mchunkptr ap = (mchunkptr)(( ((int)(m) + mask) & -align) - SIZE_SZ); size_t gap = (size_t )(ap) - (size_t )(p); size_t room; /* we need to give back leading space in a chunk of at least MINSIZE */ if (gap < MINSIZE) { /* This works since align >= MINSIZE */ /* and we've malloc'd enough total room */ ap = (mchunkptr)( (int)(ap) + align ); gap += align; } if (gap + nb > p->size) /* can't happen unless chunk sizes corrupted */ malloc_user_error(); room = p->size - gap; /* give back leader */ set_size(p, gap); consollink(p); /* use the rest */ p = ap; set_size(p, room); } /* also give back spare room at the end */ split(p, nb); UPDATE_STATS(do_malloc_stats(p)); return chunk2mem(p); }
//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*/ }