typedef struct AllocBlockData
{
AllocSet aset; /* aset that owns this block */
- AllocBlock next; /* next block in aset's blocks list */
+ AllocBlock prev; /* prev block in aset's blocks list, if any */
+ AllocBlock next; /* next block in aset's blocks list, if any */
char *freeptr; /* start of free space in this block */
char *endptr; /* end of space in this block */
} AllocBlockData;
block->aset = set;
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
block->endptr = ((char *) block) + blksize;
+ block->prev = NULL;
block->next = set->blocks;
+ if (block->next)
+ block->next->prev = block;
set->blocks = block;
/* Mark block as not to be released at reset time */
set->keeper = block;
VALGRIND_MAKE_MEM_NOACCESS(datastart, block->freeptr - datastart);
#endif
block->freeptr = datastart;
+ block->prev = NULL;
block->next = NULL;
}
else
#endif
/*
- * Stick the new block underneath the active allocation block, so that
- * we don't lose the use of the space remaining therein.
+ * Stick the new block underneath the active allocation block, if any,
+ * so that we don't lose the use of the space remaining therein.
*/
if (set->blocks != NULL)
{
+ block->prev = set->blocks;
block->next = set->blocks->next;
+ if (block->next)
+ block->next->prev = block;
set->blocks->next = block;
}
else
{
+ block->prev = NULL;
block->next = NULL;
set->blocks = block;
}
VALGRIND_MAKE_MEM_NOACCESS(block->freeptr,
blksize - ALLOC_BLOCKHDRSZ);
+ block->prev = NULL;
block->next = set->blocks;
+ if (block->next)
+ block->next->prev = block;
set->blocks = block;
}
{
/*
* Big chunks are certain to have been allocated as single-chunk
- * blocks. Find the containing block and return it to malloc().
+ * blocks. Just unlink that block and return it to malloc().
*/
- AllocBlock block = set->blocks;
- AllocBlock prevblock = NULL;
+ AllocBlock block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
- while (block != NULL)
- {
- if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ))
- break;
- prevblock = block;
- block = block->next;
- }
- if (block == NULL)
+ /*
+ * Try to verify that we have a sane block pointer: it should
+ * reference the correct aset, and freeptr and endptr should point
+ * just past the chunk.
+ */
+ if (block->aset != set ||
+ block->freeptr != block->endptr ||
+ block->freeptr != ((char *) block) +
+ (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
elog(ERROR, "could not find block containing chunk %p", chunk);
- /* let's just make sure chunk is the only one in the block */
- Assert(block->freeptr == ((char *) block) +
- (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ));
/* OK, remove block from aset's list and free it */
- if (prevblock == NULL)
- set->blocks = block->next;
+ if (block->prev)
+ block->prev->next = block->next;
else
- prevblock->next = block->next;
+ set->blocks = block->next;
+ if (block->next)
+ block->next->prev = block->prev;
#ifdef CLOBBER_FREED_MEMORY
wipe_mem(block, block->freeptr - ((char *) block));
#endif
if (oldsize > set->allocChunkLimit)
{
/*
- * The chunk must have been allocated as a single-chunk block. Find
- * the containing block and use realloc() to make it bigger with
- * minimum space wastage.
+ * The chunk must have been allocated as a single-chunk block. Use
+ * realloc() to make the containing block bigger with minimum space
+ * wastage.
*/
- AllocBlock block = set->blocks;
- AllocBlock prevblock = NULL;
+ AllocBlock block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
Size chksize;
Size blksize;
- while (block != NULL)
- {
- if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ))
- break;
- prevblock = block;
- block = block->next;
- }
- if (block == NULL)
+ /*
+ * Try to verify that we have a sane block pointer: it should
+ * reference the correct aset, and freeptr and endptr should point
+ * just past the chunk.
+ */
+ if (block->aset != set ||
+ block->freeptr != block->endptr ||
+ block->freeptr != ((char *) block) +
+ (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
elog(ERROR, "could not find block containing chunk %p", chunk);
- /* let's just make sure chunk is the only one in the block */
- Assert(block->freeptr == ((char *) block) +
- (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ));
/* Do the realloc */
chksize = MAXALIGN(size);
/* Update pointers since block has likely been moved */
chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
pointer = AllocChunkGetPointer(chunk);
- if (prevblock == NULL)
- set->blocks = block;
+ if (block->prev)
+ block->prev->next = block;
else
- prevblock->next = block;
+ set->blocks = block;
+ if (block->next)
+ block->next->prev = block;
chunk->size = chksize;
#ifdef MEMORY_CONTEXT_CHECKING
/* set mark to catch clobber of "unused" space */
if (size < chunk->size)
- set_sentinel(AllocChunkGetPointer(chunk), size);
+ set_sentinel(pointer, size);
#else /* !MEMORY_CONTEXT_CHECKING */
/*
/* Make any trailing alignment padding NOACCESS. */
VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size, chksize - size);
- return AllocChunkGetPointer(chunk);
+
+ return pointer;
}
else
{
{
AllocSet set = (AllocSet) context;
char *name = set->header.name;
+ AllocBlock prevblock;
AllocBlock block;
- for (block = set->blocks; block != NULL; block = block->next)
+ for (prevblock = NULL, block = set->blocks;
+ block != NULL;
+ prevblock = block, block = block->next)
{
char *bpoz = ((char *) block) + ALLOC_BLOCKHDRSZ;
long blk_used = block->freeptr - bpoz;
name, block);
}
+ /*
+ * Check block header fields
+ */
+ if (block->aset != set ||
+ block->prev != prevblock ||
+ block->freeptr < bpoz ||
+ block->freeptr > block->endptr)
+ elog(WARNING, "problem in alloc set %s: corrupt header in block %p",
+ name, block);
+
/*
* Chunk walker
*/