From cedda2084d2f6b331ba0a73e05f0b77ee7995c86 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Mon, 24 Dec 2012 17:11:18 +0000 Subject: Sneaky valgrind trick to detect stack memory issues. After something is popped from a stack, we overwrite the memory with uninitialised data (if JQ_DEBUG is on). This means that valgrind reports use-after-pop as an uninitialised memory error. --- forkable_stack.h | 13 +++++++++++-- jv_alloc.c | 9 +++++++++ jv_alloc.h | 11 +++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/forkable_stack.h b/forkable_stack.h index c96c132e..74fcf433 100644 --- a/forkable_stack.h +++ b/forkable_stack.h @@ -100,13 +100,22 @@ static void* forkable_stack_peek_next(struct forkable_stack* s, void* top) { // Returns 1 if the next forkable_stack_pop will permanently remove an // object from the stack (i.e. the top object was not saved with a fork) static int forkable_stack_pop_will_free(struct forkable_stack* s) { - return s->pos < s->savedlimit ? 1 : 0; + return s->pos < s->savedlimit; } static void forkable_stack_pop(struct forkable_stack* s) { forkable_stack_check(s); struct forkable_stack_header* elem = forkable_stack_peek(s); - s->pos += elem->next_delta; + int reclaim_upto = s->pos + elem->next_delta < s->savedlimit ? + s->pos + elem->next_delta : s->savedlimit; + assert(reclaim_upto <= s->length); + int reclaimed = reclaim_upto > s->pos ? reclaim_upto - s->pos : 0; + assert(0 <= reclaimed && s->pos + reclaimed <= s->length); + // s->pos <= i < reclaim_upto means that position i is to be freed + assert((reclaimed > 0) == forkable_stack_pop_will_free(s)); + int new_pos = s->pos + elem->next_delta; + jv_mem_invalidate(elem, reclaimed); + s->pos = new_pos; } diff --git a/jv_alloc.c b/jv_alloc.c index 320f16e1..e127029d 100644 --- a/jv_alloc.c +++ b/jv_alloc.c @@ -26,3 +26,12 @@ void* jv_mem_realloc(void* p, size_t sz) { } return p; } + +#if JQ_DEBUG +volatile char jv_mem_uninitialised; +__attribute__((constructor)) void jv_mem_uninit_setup(){ + char* p = malloc(1); + jv_mem_uninitialised = *p; + free(p); +} +#endif diff --git a/jv_alloc.h b/jv_alloc.h index 0613d587..b4e72c0d 100644 --- a/jv_alloc.h +++ b/jv_alloc.h @@ -3,6 +3,17 @@ #include +#if JQ_DEBUG +extern volatile char jv_mem_uninitialised; +#endif + +static void jv_mem_invalidate(void* mem, size_t n) { +#if JQ_DEBUG + char* m = mem; + while (n--) *m++ ^= jv_mem_uninitialised ^ jv_mem_uninitialised; +#endif +} + void* jv_mem_alloc(size_t); void jv_mem_free(void*); __attribute__((warn_unused_result)) void* jv_mem_realloc(void*, size_t); -- cgit v1.2.3