diff --git a/src/block_alloc.h b/src/block_alloc.h index dd5e27cea77936dc5d2b088adeefe2d15262d187..a698c6dad6103840f6a4e2b977ade6902949aabe 100644 --- a/src/block_alloc.h +++ b/src/block_alloc.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: block_alloc.h,v 1.78 2006/01/24 07:32:22 mast Exp $ +|| $Id: block_alloc.h,v 1.79 2006/01/24 12:00:49 mast Exp $ */ #undef PRE_INIT_BLOCK @@ -110,6 +110,7 @@ static struct PIKE_CONCAT(DATA,_context) *PIKE_CONCAT(DATA,_ctxs)=0; \ static struct PIKE_CONCAT(DATA,_block) *PIKE_CONCAT(DATA,_blocks)=0; \ \ /* Points to the last meta-block in the DATA,_block list that isn't full. */ \ +/* -1 when the block alloc isn't initialized. */ \ static struct PIKE_CONCAT(DATA,_block) *PIKE_CONCAT(DATA,_free_blocks)= \ (void*)-1; \ \ @@ -214,36 +215,49 @@ struct DATA *PIKE_CONCAT(alloc_,DATA)(void) \ }) \ \ DO_IF_DMALLOC( \ -static void PIKE_CONCAT(check_free_,DATA)(struct DATA *d) \ -{ \ - struct PIKE_CONCAT(DATA,_block) *tmp; \ - struct PIKE_CONCAT(DATA,_context) *ctx = PIKE_CONCAT(DATA,_ctxs); \ - for(tmp=PIKE_CONCAT(DATA,_blocks);tmp;tmp=tmp->next) \ - { \ - if( (char *)d < (char *)tmp) continue; \ - if( (char *)d >= (char *)(tmp->x+(BSIZE))) continue; \ - if ((char *) d - (char *) tmp->x != \ - (d - tmp->x) * (ptrdiff_t) sizeof (struct DATA)) break; \ - return; \ - } \ - while (ctx) { \ - for(tmp=ctx->blocks; tmp; tmp=tmp->next) \ - { \ - if( (char *)d < (char *)tmp) continue; \ - if( (char *)d >= (char *)(tmp->x+(BSIZE))) continue; \ - if ((char *) d - (char *) tmp->x != \ - (d - tmp->x) * (ptrdiff_t) sizeof (struct DATA)) break; \ - return; \ - } \ - ctx = ctx->next; \ - } \ - Pike_fatal("really_free_%s called on non-block_alloc region (%p).\n", \ - #DATA, d); \ -} \ +static void PIKE_CONCAT3(dmalloc_,DATA,_not_freed) (struct DATA *d, \ + const char *msg) \ +{ \ + /* Separate function to allow gdb breakpoints. */ \ + fprintf (stderr, "struct " TOSTR(DATA) \ + " at %p is still in use %s\n", d, msg); \ +} \ + \ +static void PIKE_CONCAT(dmalloc_late_free_,DATA) (struct DATA *d) \ +{ \ + /* Separate function to allow gdb breakpoints. */ \ + fprintf (stderr, "struct " TOSTR(DATA) " at %p freed now (too late)\n", d); \ + dmalloc_mark_as_free (d, 1); \ + dmalloc_unregister (d, 1); \ + PIKE_MEM_NA (*d); \ +} \ \ -static void PIKE_CONCAT (dmalloc_describe_, DATA) (struct DATA *d) \ +static void PIKE_CONCAT3(dmalloc_free_,DATA,_block) ( \ + struct PIKE_CONCAT(DATA,_block) *blk, const char *msg) \ { \ - DMALLOC_DESCRIBE_BLOCK (d); \ + int dont_free = 0; \ + size_t i; \ + for (i = 0; i < (BSIZE); i++) { \ + if (dmalloc_check_allocated (blk->x + i, 1)) { \ + PIKE_CONCAT3(dmalloc_,DATA,_not_freed) (blk->x + i, msg); \ + dont_free = 1; \ + DMALLOC_DESCRIBE_BLOCK ((blk->x + i)); \ + debug_malloc_dump_references (blk->x + i, 0, 2, 0); \ + } \ + else \ + dmalloc_unregister(blk->x + i, 1); \ + } \ + if (dont_free) { \ + /* If a block still is in use we conciously leak this */ \ + /* meta-block to allow access to it later. That way we can */ \ + /* avoid fatals before the leak report. */ \ + dmalloc_accept_leak (blk); \ + } \ + else { \ + /* Mark meta-block as available, since libc will mess with it. */ \ + PIKE_MEM_RW (blk->x); \ + free ((char *) blk); \ + } \ } \ ) \ \ @@ -257,37 +271,53 @@ void PIKE_CONCAT(really_free_,DATA)(struct DATA *d) \ \ DO_IF_DMALLOC({ \ struct DATA *d2; \ - PIKE_CONCAT(check_free_,DATA)(d); \ - dmalloc_mark_as_free(d, 1); \ blk = PIKE_CONCAT(DATA,_free_blocks); \ if(blk == NULL || (char *)d < (char *)blk || \ (char *)d >= (char *)(blk->x+(BSIZE))) { \ blk = PIKE_CONCAT(DATA,_blocks); \ - while((char *)d < (char *)blk || \ - (char *)d >= (char *)(blk->x+(BSIZE))) \ + while (blk && ((char *)d < (char *)blk || \ + (char *)d >= (char *)(blk->x+(BSIZE)))) \ blk = blk->next; \ } \ - blk->used--; \ - PIKE_MEM_NA(*d); \ - d2 = PIKE_CONCAT(DATA,s_to_free)[PIKE_CONCAT(DATA,s_to_free_ptr)]; \ - PIKE_CONCAT(DATA,s_to_free)[PIKE_CONCAT(DATA,s_to_free_ptr)] = d; \ - PIKE_CONCAT(DATA,s_to_free_ptr) = \ - (PIKE_CONCAT(DATA,s_to_free_ptr) + 1) % \ - NELEM(PIKE_CONCAT(DATA,s_to_free)); \ - if ((d = d2)) \ - PIKE_MEM_WO(*d); \ - else \ + if (blk) { \ + if (!dmalloc_check_allocated (d, 0)) \ + Pike_fatal ("really_free_" TOSTR(DATA) " called with " \ + "unknown pointer %p (probably already freed)\n", d); \ + blk->used--; \ + dmalloc_mark_as_free(d, 1); \ + PIKE_MEM_NA(*d); \ + d2 = PIKE_CONCAT(DATA,s_to_free)[PIKE_CONCAT(DATA,s_to_free_ptr)]; \ + PIKE_CONCAT(DATA,s_to_free)[PIKE_CONCAT(DATA,s_to_free_ptr)] = d; \ + PIKE_CONCAT(DATA,s_to_free_ptr) = \ + (PIKE_CONCAT(DATA,s_to_free_ptr) + 1) % \ + NELEM(PIKE_CONCAT(DATA,s_to_free)); \ + if ((d = d2)) \ + PIKE_MEM_WO(*d); \ + else \ + return; \ + } \ + else if (dmalloc_check_allocated (d, 0)) { \ + PIKE_CONCAT(dmalloc_late_free_,DATA) (d); \ return; \ + } \ }); \ \ blk = PIKE_CONCAT(DATA,_free_blocks); \ if(blk == NULL || (char *)d < (char *)blk || \ (char *)d >= (char *)(blk->x+(BSIZE))) { \ blk = PIKE_CONCAT(DATA,_blocks); \ + DO_IF_DEBUG ( \ + if (!blk) Pike_fatal ("really_free_" TOSTR(DATA) \ + " got invalid pointer %p\n", d) \ + ); \ if((char *)d < (char *)blk || \ (char *)d >= (char *)(blk->x+(BSIZE))) { \ do { \ blk = blk->next; \ + DO_IF_DEBUG ( \ + if (!blk) Pike_fatal ("really_free_" TOSTR(DATA) \ + " got invalid pointer %p\n", d) \ + ); \ } while((char *)d < (char *)blk || \ (char *)d >= (char *)(blk->x+(BSIZE))); \ if(blk == PIKE_CONCAT(DATA,_free_blocks)) \ @@ -304,6 +334,13 @@ void PIKE_CONCAT(really_free_,DATA)(struct DATA *d) \ PIKE_CONCAT(DATA,_free_blocks) = blk; \ } \ \ + DO_IF_DEBUG ( \ + if ((char *) d < (char *) &blk->x || \ + ((char *) d - (char *) &blk->x) % sizeof (struct DATA)) \ + Pike_fatal ("really_free_" TOSTR(DATA) \ + " got misaligned pointer %p\n", d); \ + ); \ + \ DO_PRE_INIT_BLOCK(d); \ d->BLOCK_ALLOC_NEXT = (void *)blk->PIKE_CONCAT3(free_,DATA,s); \ blk->PIKE_CONCAT3(free_,DATA,s)=d; \ @@ -323,19 +360,16 @@ void PIKE_CONCAT(really_free_,DATA)(struct DATA *d) \ blk->next->prev = NULL; \ } \ \ - DO_IF_DMALLOC({ \ - size_t i; \ - for (i = 0; i < (BSIZE); i++) { \ - dmalloc_check_block_free( \ - blk->x + i, DMALLOC_LOCATION(), #DATA, \ - (describe_block_fn *) PIKE_CONCAT (dmalloc_describe_, DATA)); \ - dmalloc_unregister(blk->x + i, 1); \ - } \ - }); \ + DO_IF_DMALLOC ( \ + PIKE_CONCAT3(dmalloc_free_,DATA,_block) ( \ + blk, "in block expected to be empty") \ + ); \ + DO_IF_NOT_DMALLOC( \ + /* Mark meta-block as available, since libc will mess with it. */ \ + PIKE_MEM_RW(*blk); \ + free(blk); \ + ); \ \ - /* Mark meta-block as available, since libc will mess with it. */ \ - PIKE_MEM_RW(*blk); \ - free(blk); \ --PIKE_CONCAT3(num_empty_,DATA,_blocks); \ } \ \ @@ -345,27 +379,26 @@ void PIKE_CONCAT(really_free_,DATA)(struct DATA *d) \ static void PIKE_CONCAT3(free_all_,DATA,_blocks_unlocked)(void) \ { \ struct PIKE_CONCAT(DATA,_block) *tmp; \ - DO_IF_DMALLOC( \ - MEMSET(PIKE_CONCAT(DATA,s_to_free), 0, sizeof(PIKE_CONCAT(DATA,s_to_free))); \ - for(tmp=PIKE_CONCAT(DATA,_blocks);tmp;tmp=tmp->next) \ - { \ - size_t tmp2; \ - for(tmp2=0;tmp2<(BSIZE);tmp2++) \ - { \ - dmalloc_check_block_free( \ - tmp->x+tmp2, DMALLOC_LOCATION(), #DATA, \ - (describe_block_fn *) PIKE_CONCAT (dmalloc_describe_, DATA)); \ - dmalloc_unregister(tmp->x+tmp2, 1); \ - } \ - } \ - ) \ - while((tmp=PIKE_CONCAT(DATA,_blocks))) \ - { \ - PIKE_CONCAT(DATA,_blocks)=tmp->next; \ - /* Mark meta-block as available, since libc will mess with it. */ \ - PIKE_MEM_RW(tmp->x); \ - free((char *)tmp); \ - } \ + \ + DO_IF_DMALLOC( \ + MEMSET(PIKE_CONCAT(DATA,s_to_free), 0, sizeof(PIKE_CONCAT(DATA,s_to_free))); \ + while ((tmp = PIKE_CONCAT(DATA,_blocks))) { \ + PIKE_CONCAT(DATA,_blocks) = tmp->next; \ + PIKE_CONCAT3(dmalloc_free_,DATA,_block) ( \ + tmp, "in free_all_" TOSTR(DATA) "_blocks"); \ + } \ + ); \ + \ + DO_IF_NOT_DMALLOC( \ + while((tmp=PIKE_CONCAT(DATA,_blocks))) \ + { \ + PIKE_CONCAT(DATA,_blocks)=tmp->next; \ + /* Mark meta-block as available, since libc will mess with it. */ \ + PIKE_MEM_RW(tmp->x); \ + free((char *)tmp); \ + } \ + ); \ + \ if (PIKE_CONCAT(DATA,_ctxs)) { \ struct PIKE_CONCAT(DATA, _context) *ctx = PIKE_CONCAT(DATA,_ctxs); \ PIKE_CONCAT(DATA,_blocks)=ctx->blocks; \