static Block* sec_block_create (size_t size, const char *during_tag) { Block *block; Cell *cell; ASSERT (during_tag); /* We can force all all memory to be malloced */ if (getenv ("SECMEM_FORCE_FALLBACK")) return NULL; block = pool_alloc (); if (!block) return NULL; cell = pool_alloc (); if (!cell) { pool_free (block); return NULL; } /* The size above is a minimum, we're free to go bigger */ if (size < DEFAULT_BLOCK_SIZE) size = DEFAULT_BLOCK_SIZE; block->words = sec_acquire_pages (&size, during_tag); block->n_words = size / sizeof (word_t); if (!block->words) { pool_free (block); pool_free (cell); return NULL; } #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (block->words, size); #endif /* The first cell to allocate from */ cell->words = block->words; cell->n_words = block->n_words; cell->requested = 0; sec_write_guards (cell); sec_insert_cell_ring (&block->unused_cells, cell); block->next = all_blocks; all_blocks = block; return block; }
static void* sec_free (Block *block, void *memory) { Cell *cell, *other; word_t *word; ASSERT (block); ASSERT (memory); word = memory; --word; #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif /* Lookup the meta for this memory block (using guard pointer) */ ASSERT (sec_is_valid_word (block, word)); ASSERT (pool_valid (*word)); cell = *word; #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (cell->words, cell->n_words * sizeof (word_t)); #endif sec_check_guards (cell); sec_clear_memory (memory, 0, cell->allocated); sec_check_guards (cell); ASSERT (cell->next == NULL); ASSERT (cell->prev == NULL); ASSERT (cell->allocated > 0); /* Find previous unallocated neighbor, and merge if possible */ other = sec_neighbor_before (block, cell); if (other && other->allocated == 0) { ASSERT (other->next && other->prev); other->n_words += cell->n_words; sec_write_guards (other); pool_free (cell); cell = other; } /* Find next unallocated neighbor, and merge if possible */ other = sec_neighbor_after (block, cell); if (other && other->allocated == 0) { ASSERT (other->next && other->prev); other->n_words += cell->n_words; other->words = cell->words; if (cell->next) sec_remove_cell_ring (&block->unused, cell); sec_write_guards (other); pool_free (cell); cell = other; } /* Add to the unused list if not already there */ if (!cell->next) sec_insert_cell_ring (&block->unused, cell); cell->allocated = 0; --block->used; return NULL; }
static void* sec_alloc (Block *block, const char *tag, size_t length) { Cell *cell, *other; size_t n_words; void *memory; ASSERT (block); ASSERT (length); ASSERT (tag); if (!block->unused_cells) return NULL; /* * Each memory allocation is aligned to a pointer size, and * then, sandwidched between two pointers to its meta data. * These pointers also act as guards. * * We allocate memory in units of sizeof (void*) */ n_words = sec_size_to_words (length) + 2; /* Look for a cell of at least our required size */ cell = block->unused_cells; while (cell->n_words < n_words) { cell = cell->next; if (cell == block->unused_cells) { cell = NULL; break; } } if (!cell) return NULL; ASSERT (cell->tag == NULL); ASSERT (cell->requested == 0); ASSERT (cell->prev); ASSERT (cell->words); sec_check_guards (cell); /* Steal from the cell if it's too long */ if (cell->n_words > n_words + WASTE) { other = pool_alloc (); if (!other) return NULL; other->n_words = n_words; other->words = cell->words; cell->n_words -= n_words; cell->words += n_words; sec_write_guards (other); sec_write_guards (cell); cell = other; } if (cell->next) sec_remove_cell_ring (&block->unused_cells, cell); ++block->n_used; cell->tag = tag; cell->requested = length; sec_insert_cell_ring (&block->used_cells, cell); memory = sec_cell_to_memory (cell); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_UNDEFINED (memory, length); #endif return memset (memory, 0, length); }