Browse Source

Added consistency checks, which revealed errors.

main
Titouan Rigoudy 11 years ago
parent
commit
a45ac0a6c5
8 changed files with 213 additions and 34 deletions
  1. +76
    -15
      ya_block.c
  2. +5
    -0
      ya_block.h
  3. +5
    -0
      ya_debug.h
  4. +75
    -8
      ya_freelist.c
  5. +7
    -0
      ya_freelist.h
  6. +30
    -10
      yamalloc.c
  7. +1
    -1
      yamalloc.h
  8. +14
    -0
      yatest.c

+ 76
- 15
ya_block.c View File

@ -61,21 +61,6 @@ static inline intptr_t inner_bytes(intptr_t *block) {
/* Function definitions */
/*----------------------*/
#ifdef YA_DEBUG
void block_print_range(intptr_t *start, intptr_t *end) {
if (!start || !end) {
return;
}
intptr_t *block;
intptr_t size;
for (block = start; block < end; block += size) {
size = block_size(block);
ya_debug("%d %p:%ld\n",
block_is_alloc(block), block, size);
}
}
#endif
/* Initializes the block's boundary tags. */
void block_init(intptr_t *block, intptr_t size) {
block[-1] = size;
@ -234,3 +219,79 @@ intptr_t *heap_extend(size_t n_bytes) {
ya_print_blocks();
return block;
}
#ifdef YA_DEBUG
/* Checks one block for consistency. Does not check the free list tags.
* Returns -1 on error, 0 otherwise. */
int block_check(intptr_t *block) {
if ((intptr_t) block & (WORD_SIZE-1)) {
ya_debug("block_check(%p): not aligned\n", block);
return -1;
}
intptr_t size = block_size(block);
if (size & 1) {
ya_debug("block_check(%p): size %ld not aligned\n", block, size);
return -1;
}
if (block[-1] != block[size-4]) {
ya_debug("block_check(%p): tags don't match %ld != %ld\n",
block, block[-1], block[size-4]);
return -1;
}
return 0;
}
/* Checks the heap and each block for consistency.
* Does not check the free list.
* Returns -1 on error, the total number of free blocks otherwise. */
int heap_check() {
if (!heap_start || !heap_end) {
ya_debug("heap_check: heap not initialized correctly %p-%p\n",
heap_start, heap_end);
return -1;
}
if ((intptr_t) heap_start & (WORD_SIZE-1)) {
ya_debug("heap_check: heap start %p not aligned\n", heap_start);
return -1;
}
if ((intptr_t) heap_end & (WORD_SIZE-1)) {
ya_debug("heap_check: heap end %p not aligned\n", heap_end);
return -1;
}
if ((heap_end - heap_start) & 1) {
ya_debug("heap_check: heap size %p not aligned\n",
heap_end - heap_start);
return -1;
}
int num_free = 0;
bool prev_free = false;
intptr_t *block;
for (block = heap_start; block < heap_end; block += block_size(block)) {
if (block_check(block)) {
return -1;
}
if (prev_free && !block_is_alloc(block)) {
ya_debug("heap_check: block %p and prev are both free\n", block);
return -1;
}
prev_free = !block_is_alloc(block);
num_free += prev_free;
}
return num_free;
}
void block_print_range(intptr_t *start, intptr_t *end) {
if (!start || !end) {
return;
}
intptr_t *block;
intptr_t size;
for (block = start; block < end; block += size) {
size = block_size(block);
ya_debug("%d %p:%ld\n",
block_is_alloc(block), block, size);
}
}
#endif //def YA_DEBUG

+ 5
- 0
ya_block.h View File

@ -71,6 +71,11 @@ intptr_t *heap_extend(size_t n_bytes);
#ifdef YA_DEBUG
/* Prints each block in the range from the block at start to the one at end */
void block_print_range(intptr_t *start, intptr_t *end);
/* Checks the heap and each block for consistency.
* Does not check the free list.
* Returns -1 on error, the total number of free blocks otherwise. */
int heap_check();
#endif
/* Initializes the block's boundary tags. */


+ 5
- 0
ya_debug.h View File

@ -14,10 +14,15 @@
void ya_print_blocks();
/* Checks internal state for errors.
* Returns -1 on error, 0 otherwise. */
int ya_check();
#else
#define ya_debug(...)
#define ya_print_blocks(...)
#define ya_check(...)
#endif // def YA_DEBUG


+ 75
- 8
ya_freelist.c View File

@ -23,14 +23,6 @@ intptr_t *fl_end = NULL; // sorted decreasing
/* Functions */
/*-----------*/
#ifdef YA_DEBUG
void fl_debug_print() {
for (intptr_t *block = fl_start; block != NULL; block = fl_next(block)) {
ya_debug("%p:%ld\n", block, block_size(block));
}
}
#endif
/* Splices the allocated block out of the free list. */
void fl_alloc(intptr_t *block) {
intptr_t size = block_size(block);
@ -157,3 +149,78 @@ intptr_t *fl_get_start() {
intptr_t *fl_get_end() {
return fl_end;
}
#ifdef YA_DEBUG
void fl_debug_print() {
for (intptr_t *block = fl_start; block != NULL; block = fl_next(block)) {
ya_debug("%p:%ld\n", block, block_size(block));
}
}
/* Checks that block's information is consistent. The previous pointer should
* point to correct_prev, which was the previous free block during free list
* iteration.
* Returns -1 on error, 0 otherwise. */
int fl_check_one(intptr_t *block, intptr_t *correct_prev) {
if (block < heap_start || block >= heap_end) {
ya_debug("fl_check_one: block %p out of bounds\n", block);
return -1;
}
intptr_t *prev = fl_prev(block);
if (prev && (prev < heap_start || prev >= heap_end)) {
ya_debug("fl_check_one: previous pointer %p out of bounds [%p,%p[\n",
prev, heap_start, heap_end);
return -1;
}
if (correct_prev != prev) {
ya_debug("fl_check_one(%p): previous pointer mismatch, "
"should be %p, not %p\n", block, correct_prev, prev);
return -1;
}
intptr_t *next = fl_next(block);
if (next && (next < heap_start || next >= heap_end)) {
ya_debug("fl_check_one: next pointer %p out of bounds [%p,%p[\n",
next, heap_start, heap_end);
return -1;
}
return 0;
}
/* Checks the free list for consistency.
* Returns -1 on error, the total number of free blocks otherwise. */
int fl_check() {
if (!fl_start) {
if (fl_end) {
ya_debug("fl_check: fl_start == NULL but fl_end == %p\n", fl_end);
return -1;
}
return 0;
}
if (!fl_end) {
ya_debug("fl_check: fl_end == NULL but fl_start == %p\n", fl_start);
return -1;
}
if (fl_start < heap_start || fl_start >= heap_end) {
ya_debug("fl_check: fl_start %p out of bounds\n", fl_start);
return -1;
}
if (fl_end < heap_start || fl_end >= heap_end) {
ya_debug("fl_check: fl_ebd %p out of bounds\n", fl_end);
return -1;
}
int num_free = 0;
intptr_t *prev = NULL;
intptr_t *block;
for (block = fl_start; block; block = fl_next(block)) {
num_free++;
if (fl_check_one(block, prev)) {
return -1;
}
prev = block;
}
return num_free;
}
#endif // def YA_DEBUG

+ 7
- 0
ya_freelist.h View File

@ -49,7 +49,14 @@ static inline void fl_set_next(intptr_t *block, intptr_t *next) {
/*--------------*/
#ifdef YA_DEBUG
/* Prints debug information about the free list. */
void fl_debug_print();
/* Checks the free list for consistency.
* Returns -1 on error, the total number of free blocks otherwise. */
int fl_check();
#endif
/* Splices the allocated block out of the free list. */


+ 30
- 10
yamalloc.c View File

@ -16,16 +16,6 @@
/* Function definitions */
/*----------------------*/
#ifdef YA_DEBUG
/* Print all blocks in the heap */
void ya_print_blocks() {
ya_debug("All blocks:\n");
block_print_range(heap_start, heap_end);
ya_debug("Free blocks:\n");
fl_debug_print();
}
#endif
/* Allocates enough memory to store at least size bytes.
* Returns a dword-aligned pointer to the memory or NULL in case of failure. */
void *malloc(size_t n_bytes) {
@ -148,3 +138,33 @@ void *realloc(void *ptr, size_t n_bytes) {
free(block);
return new_block;
}
#ifdef YA_DEBUG
/* Print all blocks in the heap */
void ya_print_blocks() {
ya_debug("All blocks:\n");
block_print_range(heap_start, heap_end);
ya_debug("Free blocks:\n");
fl_debug_print();
}
/* Checks internal state for errors.
* Returns -1 on error, 0 otherwise. */
int ya_check() {
int heap_free = heap_check();
if (heap_free == -1) {
return -1;
}
int fl_free = fl_check();
if (fl_free == -1) {
return -1;
}
if (fl_free != heap_free) {
ya_debug("ya_check: heap_check reports %d free blocks, fl_check %d\n",
heap_free, fl_free);
return -1;
}
return 0;
}
#endif

+ 1
- 1
yamalloc.h View File

@ -16,4 +16,4 @@ void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
#endif
#endif // def YAMALLOC_H

+ 14
- 0
yatest.c View File

@ -31,30 +31,44 @@ int main(int argc, char **argv) {
ya_print_blocks();
a = print_malloc(4);
ya_print_blocks();
if (ya_check()) return -1;
b = print_malloc(10);
ya_print_blocks();
if (ya_check()) return -1;
c = print_malloc(10000);
ya_print_blocks();
if (ya_check()) return -1;
d = print_malloc(2000);
ya_print_blocks();
if (ya_check()) return -1;
print_free(a);
ya_print_blocks();
if (ya_check()) return -1;
print_free(c);
ya_print_blocks();
if (ya_check()) return -1;
c = print_malloc(100);
ya_print_blocks();
if (ya_check()) return -1;
a = print_malloc(2);
ya_print_blocks();
if (ya_check()) return -1;
print_free(d);
ya_print_blocks();
if (ya_check()) return -1;
d = print_realloc(NULL, 400);
ya_print_blocks();
if (ya_check()) return -1;
d = print_realloc(d, 4000);
ya_print_blocks();
if (ya_check()) return -1;
d = print_realloc(d, 32000);
ya_print_blocks();
if (ya_check()) return -1;
d = print_realloc(d, 1000);
ya_print_blocks();
if (ya_check()) return -1;
c = print_realloc(c, 500);
ya_print_blocks();
if (ya_check()) return -1;
}

Loading…
Cancel
Save