void* egg_secure_alloc_full (const char *tag, size_t length, int flags) { Block *block; void *memory = NULL; if (tag == NULL) tag = "?"; if (length > 0xFFFFFFFF / 2) { if (egg_secure_warnings) fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", (unsigned long)length); return NULL; } /* Can't allocate zero bytes */ if (length == 0) return NULL; DO_LOCK (); for (block = all_blocks; block; block = block->next) { memory = sec_alloc (block, tag, length); if (memory) break; } /* None of the current blocks have space, allocate new */ if (!memory) { block = sec_block_create (length, tag); if (block) memory = sec_alloc (block, tag, length); } #ifdef WITH_VALGRIND if (memory != NULL) VALGRIND_MALLOCLIKE_BLOCK (memory, length, sizeof (void*), 1); #endif DO_UNLOCK (); if (!memory && (flags & EGG_SECURE_USE_FALLBACK)) { memory = egg_memory_fallback (NULL, length); if (memory) /* Our returned memory is always zeroed */ memset (memory, 0, length); } if (!memory) errno = ENOMEM; return memory; }
static void* sec_realloc (Block *block, void *memory, size_t length) { Cell *cell, *other; word_t *word; size_t n_words; size_t valid; void *alloc; /* Standard realloc behavior, should have been handled elsewhere */ ASSERT (memory != NULL); ASSERT (length > 0); /* Dig out where the meta should be */ word = memory; --word; #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (word, sizeof (word_t)); #endif ASSERT (sec_is_valid_word (block, word)); ASSERT (pool_valid (*word)); cell = *word; /* Validate that it's actually for real */ sec_check_guards (cell); ASSERT (cell->allocated > 0); ASSERT (cell->next == NULL); ASSERT (cell->prev == NULL); /* The amount of valid data */ valid = cell->allocated; /* How many words we actually want */ n_words = sec_size_to_words (length) + 2; /* Less memory is required than is in the cell */ if (n_words <= cell->n_words) { /* TODO: No shrinking behavior yet */ cell->allocated = length; alloc = sec_cell_to_memory (cell); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (alloc, length); #endif /* * Even though we may be reusing the same cell, that doesn't * mean that the allocation is shrinking. It could have shrunk * and is now expanding back some. */ if (length < valid) return sec_clear_memory (alloc, length, valid); else return alloc; } /* Need braaaaaiiiiiinsss... */ while (cell->n_words < n_words) { /* See if we have a neighbor who can give us some memory */ other = sec_neighbor_after (block, cell); if (!other || other->allocated != 0) break; /* Eat the whole neighbor if not too big */ if (n_words - cell->n_words + WASTE >= other->n_words) { cell->n_words += other->n_words; sec_write_guards (cell); sec_remove_cell_ring (&block->unused, other); pool_free (other); /* Steal from the neighbor */ } else { other->words += n_words - cell->n_words; other->n_words -= n_words - cell->n_words; sec_write_guards (other); cell->n_words = n_words; sec_write_guards (cell); } } if (cell->n_words >= n_words) { cell->allocated = length; alloc = sec_cell_to_memory (cell); #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (alloc, length); #endif return sec_clear_memory (alloc, valid, length); } /* That didn't work, try alloc/free */ alloc = sec_alloc (block, length); if (alloc) { memcpy (alloc, memory, valid); sec_free (block, memory); } return alloc; }