diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index ec3e264a73..fbe33ad87e 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -150,11 +150,13 @@ typedef AllocSetContext *AllocSet; */ typedef struct AllocBlockData { - AllocSet aset; /* aset that owns this block */ 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 */ +#ifdef MEMORY_CONTEXT_CHECKING + AllocSet aset; /* aset that owns this block */ +#endif } AllocBlockData; /* @@ -485,11 +487,13 @@ AllocSetContextCreateInternal(MemoryContext parent, /* Fill in the initial block's block header */ block = (AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext))); - block->aset = set; block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ; block->endptr = ((char *) set) + firstBlockSize; block->prev = NULL; block->next = NULL; +#ifdef MEMORY_CONTEXT_CHECKING + block->aset = set; +#endif /* Mark unallocated space NOACCESS; leave the block header alone. */ VALGRIND_MAKE_MEM_NOACCESS(block->freeptr, block->endptr - block->freeptr); @@ -743,8 +747,10 @@ AllocSetAlloc(MemoryContext context, Size size) context->mem_allocated += blksize; - block->aset = set; block->freeptr = block->endptr = ((char *) block) + blksize; +#ifdef MEMORY_CONTEXT_CHECKING + block->aset = set; +#endif chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ); chunk->aset = set; @@ -936,9 +942,11 @@ AllocSetAlloc(MemoryContext context, Size size) context->mem_allocated += blksize; - block->aset = set; block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ; block->endptr = ((char *) block) + blksize; +#ifdef MEMORY_CONTEXT_CHECKING + block->aset = set; +#endif /* Mark unallocated space NOACCESS. */ VALGRIND_MAKE_MEM_NOACCESS(block->freeptr, @@ -1019,8 +1027,10 @@ AllocSetFree(MemoryContext context, void *pointer) * reference the correct aset, and freeptr and endptr should point * just past the chunk. */ - if (block->aset != set || - block->freeptr != block->endptr || + if (block->freeptr != block->endptr || +#ifdef MEMORY_CONTEXT_CHECKING + block->aset != set || +#endif block->freeptr != ((char *) block) + (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)) elog(ERROR, "could not find block containing chunk %p", chunk); @@ -1108,8 +1118,10 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size) * reference the correct aset, and freeptr and endptr should point * just past the chunk. */ - if (block->aset != set || - block->freeptr != block->endptr || + if (block->freeptr != block->endptr || +#ifdef MEMORY_CONTEXT_CHECKING + block->aset != set || +#endif block->freeptr != ((char *) block) + (oldsize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)) elog(ERROR, "could not find block containing chunk %p", chunk); diff --git a/src/backend/utils/mmgr/generation.c b/src/backend/utils/mmgr/generation.c index e530e272e0..55acc2b84c 100644 --- a/src/backend/utils/mmgr/generation.c +++ b/src/backend/utils/mmgr/generation.c @@ -42,6 +42,7 @@ #define Generation_BLOCKHDRSZ MAXALIGN(sizeof(GenerationBlock)) +#define Generation_CHUNKSIZEZ SIZEOF_SIZE_T #define Generation_CHUNKHDRSZ sizeof(GenerationChunk) #define Generation_CHUNK_FRACTION 8 @@ -89,7 +90,6 @@ typedef struct GenerationContext struct GenerationBlock { dlist_node node; /* doubly-linked list of blocks */ - Size blksize; /* allocated size of this block */ int nchunks; /* number of chunks in the block */ int nfree; /* number of free chunks */ char *freeptr; /* start of free space in this block */ @@ -110,16 +110,17 @@ struct GenerationBlock */ struct GenerationChunk { +#ifdef MEMORY_CONTEXT_CHECKING /* size is always the size of the usable space in the chunk */ Size size; -#ifdef MEMORY_CONTEXT_CHECKING + /* when debugging memory usage, also store actual requested size */ /* this is zero in a free chunk */ Size requested_size; #define GENERATIONCHUNK_RAWSIZE (SIZEOF_SIZE_T * 2 + SIZEOF_VOID_P * 2) #else -#define GENERATIONCHUNK_RAWSIZE (SIZEOF_SIZE_T + SIZEOF_VOID_P * 2) +#define GENERATIONCHUNK_RAWSIZE (SIZEOF_VOID_P * 2) #endif /* MEMORY_CONTEXT_CHECKING */ /* ensure proper alignment by adding padding if needed */ @@ -247,7 +248,7 @@ GenerationContextCreate(MemoryContext parent, /* Determine size of initial block */ allocSize = MAXALIGN(sizeof(GenerationContext)) + - Generation_BLOCKHDRSZ + Generation_CHUNKHDRSZ; + Generation_BLOCKHDRSZ + Generation_CHUNKHDRSZ + Generation_CHUNKSIZEZ; if (minContextSize != 0) allocSize = Max(allocSize, minContextSize); else @@ -303,8 +304,8 @@ GenerationContextCreate(MemoryContext parent, * Follows similar ideas as AllocSet, see aset.c for details ... */ set->allocChunkLimit = maxBlockSize; - while ((Size) (set->allocChunkLimit + Generation_CHUNKHDRSZ) > - (Size) ((Size) (maxBlockSize - Generation_BLOCKHDRSZ) / Generation_CHUNK_FRACTION)) + while ((Size) (set->allocChunkLimit + Generation_CHUNKHDRSZ + Generation_CHUNKSIZEZ) > + (Size) ((Size) (maxBlockSize - Generation_BLOCKHDRSZ + Generation_CHUNKSIZEZ) / Generation_CHUNK_FRACTION)) set->allocChunkLimit >>= 1; /* Finally, do the type-independent part of context creation */ @@ -399,8 +400,9 @@ GenerationAlloc(MemoryContext context, Size size) GenerationContext *set = (GenerationContext *) context; GenerationBlock *block; GenerationChunk *chunk; + char *ptr; Size chunk_size = MAXALIGN(size); - Size required_size = chunk_size + Generation_CHUNKHDRSZ; + Size required_size = chunk_size + Generation_CHUNKHDRSZ + Generation_CHUNKSIZEZ; /* is it an over-sized chunk? if yes, allocate special block */ if (chunk_size > set->allocChunkLimit) @@ -414,19 +416,22 @@ GenerationAlloc(MemoryContext context, Size size) context->mem_allocated += blksize; /* block with a single (used) chunk */ - block->blksize = blksize; block->nchunks = 1; block->nfree = 0; /* the block is completely full */ block->freeptr = block->endptr = ((char *) block) + blksize; - chunk = (GenerationChunk *) (((char *) block) + Generation_BLOCKHDRSZ); + /* Store chunk size outside chunk header */ + ptr = (((char *) block) + Generation_BLOCKHDRSZ); + memcpy(ptr, &chunk_size, Generation_CHUNKSIZEZ); + + chunk = (GenerationChunk *) (((char *) block) + Generation_BLOCKHDRSZ + Generation_CHUNKSIZEZ); chunk->block = block; chunk->context = set; - chunk->size = chunk_size; #ifdef MEMORY_CONTEXT_CHECKING + chunk->size = chunk_size; chunk->requested_size = size; /* set mark to catch clobber of "unused" space */ if (size < chunk_size) @@ -531,23 +536,27 @@ GenerationAlloc(MemoryContext context, Size size) /* we're supposed to have a block with enough free space now */ Assert(block != NULL); - Assert((block->endptr - block->freeptr) >= Generation_CHUNKHDRSZ + chunk_size); + Assert((block->endptr - block->freeptr) >= Generation_CHUNKHDRSZ + Generation_CHUNKSIZEZ + chunk_size); - chunk = (GenerationChunk *) block->freeptr; + /* Store chunk size outside chunk header */ + ptr = block->freeptr; + memcpy(ptr, &chunk_size, Generation_CHUNKSIZEZ); + + chunk = (GenerationChunk *) (block->freeptr + Generation_CHUNKSIZEZ); /* Prepare to initialize the chunk header. */ VALGRIND_MAKE_MEM_UNDEFINED(chunk, Generation_CHUNKHDRSZ); block->nchunks += 1; - block->freeptr += (Generation_CHUNKHDRSZ + chunk_size); + block->freeptr += (Generation_CHUNKSIZEZ + Generation_CHUNKHDRSZ + chunk_size); Assert(block->freeptr <= block->endptr); chunk->block = block; chunk->context = set; - chunk->size = chunk_size; #ifdef MEMORY_CONTEXT_CHECKING + chunk->size = chunk_size; chunk->requested_size = size; /* set mark to catch clobber of "unused" space */ if (size < chunk->size) @@ -576,7 +585,6 @@ GenerationAlloc(MemoryContext context, Size size) static inline void GenerationBlockInit(GenerationBlock *block, Size blksize) { - block->blksize = blksize; block->nchunks = 0; block->nfree = 0; @@ -647,10 +655,10 @@ GenerationBlockFree(GenerationContext *set, GenerationBlock *block) /* release the block from the list of blocks */ dlist_delete(&block->node); - ((MemoryContext) set)->mem_allocated -= block->blksize; + ((MemoryContext) set)->mem_allocated -= block->endptr - ((char *) block); #ifdef CLOBBER_FREED_MEMORY - wipe_mem(block, block->blksize); + wipe_mem(block, block->endptr - ((char *) block)); #endif free(block); @@ -672,6 +680,8 @@ GenerationFree(MemoryContext context, void *pointer) VALGRIND_MAKE_MEM_DEFINED(chunk, GENERATIONCHUNK_PRIVATE_LEN); block = chunk->block; + elog(LOG, "MAXALIGN(sizeof(GenerationContext))=%zu Generation_BLOCKHDRSZ=%zu Generation_CHUNKHDRSZ=%zu", + MAXALIGN(sizeof(GenerationContext)), Generation_BLOCKHDRSZ, Generation_CHUNKHDRSZ); #ifdef MEMORY_CONTEXT_CHECKING /* Test for someone scribbling on unused space in chunk */ @@ -732,7 +742,7 @@ GenerationFree(MemoryContext context, void *pointer) */ dlist_delete(&block->node); - context->mem_allocated -= block->blksize; + context->mem_allocated -= block->endptr - ((char *) block); free(block); } @@ -753,9 +763,14 @@ GenerationRealloc(MemoryContext context, void *pointer, Size size) /* Allow access to private part of chunk header. */ VALGRIND_MAKE_MEM_DEFINED(chunk, GENERATIONCHUNK_PRIVATE_LEN); - oldsize = chunk->size; + /* Read chunk size outside chunk header */ + memcpy((char *) &oldsize, ((char *) chunk) - Generation_CHUNKSIZEZ, Generation_CHUNKSIZEZ); #ifdef MEMORY_CONTEXT_CHECKING + if (oldsize != chunk->size) + elog(WARNING, "detected wrong chunk size %s %p", + ((MemoryContext) set)->name, chunk); + /* Test for someone scribbling on unused space in chunk */ if (chunk->requested_size < oldsize) if (!sentinel_ok(pointer, chunk->requested_size)) @@ -862,12 +877,21 @@ static Size GenerationGetChunkSpace(MemoryContext context, void *pointer) { GenerationChunk *chunk = GenerationPointerGetChunk(pointer); - Size result; + Size size; + + /* Read chunk size outside chunk header */ + memcpy((char *) &size, ((char *) chunk) - Generation_CHUNKSIZEZ, Generation_CHUNKSIZEZ); + +#ifdef MEMORY_CONTEXT_CHECKING + if (size != chunk->size) + elog(WARNING, "detected wrong chunk size %s %p", + ((MemoryContext) set)->name, chunk); +#endif VALGRIND_MAKE_MEM_DEFINED(chunk, GENERATIONCHUNK_PRIVATE_LEN); - result = chunk->size + Generation_CHUNKHDRSZ; + size += Generation_CHUNKHDRSZ + Generation_CHUNKSIZEZ; VALGRIND_MAKE_MEM_NOACCESS(chunk, GENERATIONCHUNK_PRIVATE_LEN); - return result; + return size; } /* @@ -926,7 +950,7 @@ GenerationStats(MemoryContext context, nblocks++; nchunks += block->nchunks; nfreechunks += block->nfree; - totalspace += block->blksize; + totalspace += block->endptr - ((char *) block); freespace += (block->endptr - block->freeptr); } @@ -977,7 +1001,7 @@ GenerationCheck(MemoryContext context) nchunks; char *ptr; - total_allocated += block->blksize; + total_allocated += block->endptr - ((char *) block); /* * nfree > nchunks is surely wrong. Equality is allowed as the block