/* * Author: Garrett Barboza * * Copyright (c) 2014 Kaprica Security, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ #include "libcgc.h" #include "cgc_malloc.h" #include "cgc_stdlib.h" /* Get some more memory through allocate */ static int allocate_new_blk(void) { void *ret; struct blk_t *new_blk; cgc_size_t size = NEW_CHUNK_SIZE; if (cgc_allocate(size, 0, &ret) != 0) { return 1; } if (ret == NULL) return 1; new_blk = (struct blk_t *)ret; new_blk->size = size; new_blk->free = 1; new_blk->fpred = NULL; new_blk->fsucc = NULL; new_blk->prev = NULL; new_blk->next = NULL; cgc_insert_into_flist(new_blk); return 0; } /* Find first fit block for a size */ static int find_fit(cgc_size_t size, struct blk_t **blk) { int sc_i = cgc_get_size_class(size); for (; sc_i < NUM_FREE_LISTS; sc_i++) { *blk = cgc_free_lists[sc_i]; for(; *blk != NULL; *blk = (*blk)->fsucc) if ((*blk)->size >= size) return sc_i; } *blk = NULL; return -1; } static void *malloc_huge(cgc_size_t size) { void *mem; size += HEADER_PADDING; if (cgc_allocate(size, 0, &mem) != 0) return NULL; struct blk_t *blk = mem; blk->size = size; blk->free = 0; blk->fpred = NULL; blk->fsucc = NULL; blk->prev = NULL; blk->next = NULL; return (void *)((intptr_t)blk + HEADER_PADDING); } void *cgc_malloc(cgc_size_t size) { if (size == 0) return NULL; if (size + HEADER_PADDING >= NEW_CHUNK_SIZE) return malloc_huge(size); if (size % ALIGNMENT != 0) size = (size + ALIGNMENT - 1) & ~(ALIGNMENT - 1); if (size >= 0x80000000) return NULL; size += HEADER_PADDING; struct blk_t *blk = NULL; int sc_i = find_fit(size, &blk); /* Allocate a new block if no fit */ if (blk == NULL) { if (allocate_new_blk() != 0) { return NULL; } else { sc_i = NUM_FREE_LISTS - 1; blk = cgc_free_lists[sc_i]; } } /* Remove the block we're going to use from the free list */ cgc_remove_from_flist(blk); /* Split the block into two pieces if possible */ cgc_size_t sdiff = blk->size - size; if (sdiff > 2 * HEADER_PADDING) { struct blk_t *nb = (struct blk_t *)((intptr_t)blk + size); nb->size = sdiff; nb->free = 1; nb->fsucc = NULL; nb->fpred = NULL; blk->size = size; /* Patch up blk list pointers */ nb->prev = blk; nb->next = blk->next; if (blk->next) blk->next->prev = nb; blk->next = nb; /* Put the new block into the free list */ cgc_insert_into_flist(nb); } return (void *)((intptr_t)blk + HEADER_PADDING); }