src/backend/utils/mmgr/aset.c
static void *
AllocSetRealloc(MemoryContext context, void *pointer, Size size)
{
	AllocSet	set = (AllocSet) context;
	AllocChunk	chunk = AllocPointerGetChunk(pointer);
	Size		oldsize;

	/* Allow access to private part of chunk header. */
	VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOCCHUNK_PRIVATE_LEN);

	oldsize = chunk->size;

#ifdef MEMORY_CONTEXT_CHECKING
	/* Test for someone scribbling on unused space in chunk */
	if (chunk->requested_size < oldsize)
		if (!sentinel_ok(pointer, chunk->requested_size))
			elog(WARNING, "detected write past chunk end in %s %p",
				 set->header.name, chunk);
#endif

	if (oldsize > set->allocChunkLimit)
	{
		/*
		 * The chunk must have been allocated as a single-chunk block.  Use
		 * realloc() to make the containing block bigger, or smaller, with
		 * minimum space wastage.
		 */
		AllocBlock	block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
		Size		chksize;
		Size		blksize;
		Size		oldblksize;

		/*
		 * 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) +
			(oldsize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
			elog(ERROR, "could not find block containing chunk %p", chunk);

		/*
		 * Even if the new request is less than set->allocChunkLimit, we stick
		 * with the single-chunk block approach.  Therefore we need
		 * chunk->size to be bigger than set->allocChunkLimit, so we don't get
		 * confused about the chunk's status in future calls.
		 */
		chksize = Max(size, set->allocChunkLimit + 1);
		chksize = MAXALIGN(chksize);

		/* Do the realloc */
		blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
		oldblksize = block->endptr - ((char *) block);

		block = (AllocBlock) realloc(block, blksize);
		if (block == NULL)
		{
			/* Disallow external access to private part of chunk header. */
			VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
			return NULL;
		}

		/* updated separately, not to underflow when (oldblksize > blksize) */
		context->mem_allocated -= oldblksize;
		context->mem_allocated += blksize;

		block->freeptr = block->endptr = ((char *) block) + blksize;

		/* Update pointers since block has likely been moved */
		chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
		pointer = AllocChunkGetPointer(chunk);
		if (block->prev)
			block->prev->next = block;
		else
			set->blocks = block;
		if (block->next)
			block->next->prev = block;
		chunk->size = chksize;

#ifdef MEMORY_CONTEXT_CHECKING
#ifdef RANDOMIZE_ALLOCATED_MEMORY
		/* We can only fill the extra space if we know the prior request */
		if (size > chunk->requested_size)
			randomize_mem((char *) pointer + chunk->requested_size,
						  size - chunk->requested_size);
#endif

		/*
		 * realloc() (or randomize_mem()) will have left any newly-allocated
		 * part UNDEFINED, but we may need to adjust trailing bytes from the
		 * old allocation.
		 */
#ifdef USE_VALGRIND
		if (oldsize > chunk->requested_size)
			VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + chunk->requested_size,
										oldsize - chunk->requested_size);
#endif

		chunk->requested_size = size;

		/* set mark to catch clobber of "unused" space */
		if (size < chunk->size)
			set_sentinel(pointer, size);
#else							/* !MEMORY_CONTEXT_CHECKING */

		/*
		 * We don't know how much of the old chunk size was the actual
		 * allocation; it could have been as small as one byte.  We have to be
		 * conservative and just mark the entire old portion DEFINED.
		 */
		VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
#endif

		/* Ensure any padding bytes are marked NOACCESS. */
		VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size, chksize - size);

		/* Disallow external access to private part of chunk header. */
		VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);

		return pointer;
	}

	/*
	 * Chunk sizes are aligned to power of 2 in AllocSetAlloc().  Maybe the
	 * allocated area already is >= the new size.  (In particular, we will
	 * fall out here if the requested size is a decrease.)
	 */
	else if (oldsize >= size)
	{
#ifdef MEMORY_CONTEXT_CHECKING
		Size		oldrequest = chunk->requested_size;

#ifdef RANDOMIZE_ALLOCATED_MEMORY
		/* We can only fill the extra space if we know the prior request */
		if (size > oldrequest)
			randomize_mem((char *) pointer + oldrequest,
						  size - oldrequest);
#endif

		chunk->requested_size = size;

		/*
		 * If this is an increase, mark any newly-available part UNDEFINED.
		 * Otherwise, mark the obsolete part NOACCESS.
		 */
		if (size > oldrequest)
			VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + oldrequest,
										size - oldrequest);
		else
			VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size,
									   oldsize - size);

		/* set mark to catch clobber of "unused" space */
		if (size < oldsize)
			set_sentinel(pointer, size);
#else							/* !MEMORY_CONTEXT_CHECKING */

		/*
		 * We don't have the information to determine whether we're growing
		 * the old request or shrinking it, so we conservatively mark the
		 * entire new allocation DEFINED.
		 */
		VALGRIND_MAKE_MEM_NOACCESS(pointer, oldsize);
		VALGRIND_MAKE_MEM_DEFINED(pointer, size);
#endif

		/* Disallow external access to private part of chunk header. */
		VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);

		return pointer;
	}
	else
	{
		/*
		 * Enlarge-a-small-chunk case.  We just do this by brute force, ie,
		 * allocate a new chunk and copy the data.  Since we know the existing
		 * data isn't huge, this won't involve any great memcpy expense, so
		 * it's not worth being smarter.  (At one time we tried to avoid
		 * memcpy when it was possible to enlarge the chunk in-place, but that
		 * turns out to misbehave unpleasantly for repeated cycles of
		 * palloc/repalloc/pfree: the eventually freed chunks go into the
		 * wrong freelist for the next initial palloc request, and so we leak
		 * memory indefinitely.  See pgsql-hackers archives for 2007-08-11.)
		 */
		AllocPointer newPointer;

		/* allocate new chunk */
		newPointer = AllocSetAlloc((MemoryContext) set, size);

		/* leave immediately if request was not completed */
		if (newPointer == NULL)
		{
			/* Disallow external access to private part of chunk header. */
			VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
			return NULL;
		}

		/*
		 * AllocSetAlloc() may have returned a region that is still NOACCESS.
		 * Change it to UNDEFINED for the moment; memcpy() will then transfer
		 * definedness from the old allocation to the new.  If we know the old
		 * allocation, copy just that much.  Otherwise, make the entire old
		 * chunk defined to avoid errors as we copy the currently-NOACCESS
		 * trailing bytes.
		 */
		VALGRIND_MAKE_MEM_UNDEFINED(newPointer, size);
#ifdef MEMORY_CONTEXT_CHECKING
		oldsize = chunk->requested_size;
#else
		VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
#endif

		/* transfer existing data (certain to fit) */
		memcpy(newPointer, pointer, oldsize);

		/* free old chunk */
		AllocSetFree((MemoryContext) set, pointer);

		return newPointer;
	}
}
/*
 * AllocSetRealloc
 *		Returns new pointer to allocated memory of given size or NULL if
 *		request could not be completed; this memory is added to the set.
 *		Memory associated with given pointer is copied into the new memory,
 *		and the old memory is freed.
 *
 * Without MEMORY_CONTEXT_CHECKING, we don't know the old request size.  This
 * makes our Valgrind client requests less-precise, hazarding false negatives.
 * (In principle, we could use VALGRIND_GET_VBITS() to rediscover the old
 * request size.)
 */
AllocSetRealloc
Returns new pointer to allocated memory of given size or NULL if
request could not be completed; this memory is added to the set.
Memory associated with given pointer is copied into the new memory,
and the old memory is freed.

Without MEMORY_CONTEXT_CHECKING, we don't know the old request size.  This
makes our Valgrind client requests less-precise, hazarding false negatives.
(In principle, we could use VALGRIND_GET_VBITS() to rediscover the old
request size.)
AllocSetRealloc Returns new pointer to allocated memory of given size or NULL if request could not be completed ; this memory is added to the set . Memory associated with given pointer is copied into the new memory and the old memory is freed . Without MEMORY_CONTEXT_CHECKING we don ' t know the old request size . This makes our Valgrind client requests less - precise hazarding false negatives . ( In principle we could use VALGRIND_GET_VBITS () to rediscover the old request size . )
static void *
AllocSetRealloc(MemoryContext context, void *pointer, Size size)
{
	AllocSet	set = (AllocSet) context;
	AllocChunk	chunk = AllocPointerGetChunk(pointer);
	Size		oldsize;
	VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOCCHUNK_PRIVATE_LEN);
	oldsize = chunk->size;
#ifdef MEMORY_CONTEXT_CHECKING
	if (chunk->requested_size < oldsize)
		if (!sentinel_ok(pointer, chunk->requested_size))
			elog(WARNING, "detected write past chunk end in %s %p",
				 set->header.name, chunk);
#endif
	if (oldsize > set->allocChunkLimit)
	{
		AllocBlock	block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
		Size		chksize;
		Size		blksize;
		Size		oldblksize;
		if (block->aset != set ||
			block->freeptr != block->endptr ||
			block->freeptr != ((char *) block) +
			(oldsize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
			elog(ERROR, "could not find block containing chunk %p", chunk);
		chksize = Max(size, set->allocChunkLimit + 1);
		chksize = MAXALIGN(chksize);
		blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
		oldblksize = block->endptr - ((char *) block);
		block = (AllocBlock) realloc(block, blksize);
		if (block == NULL)
		{
			VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
			return NULL;
		}
		context->mem_allocated -= oldblksize;
		context->mem_allocated += blksize;
		block->freeptr = block->endptr = ((char *) block) + blksize;
		chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
		pointer = AllocChunkGetPointer(chunk);
		if (block->prev)
			block->prev->next = block;
		else
			set->blocks = block;
		if (block->next)
			block->next->prev = block;
		chunk->size = chksize;
#ifdef MEMORY_CONTEXT_CHECKING
#ifdef RANDOMIZE_ALLOCATED_MEMORY
		if (size > chunk->requested_size)
			randomize_mem((char *) pointer + chunk->requested_size,
						  size - chunk->requested_size);
#endif
#ifdef USE_VALGRIND
		if (oldsize > chunk->requested_size)
			VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + chunk->requested_size,
										oldsize - chunk->requested_size);
#endif
		chunk->requested_size = size;
		if (size < chunk->size)
			set_sentinel(pointer, size);
#else							
		VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
#endif
		VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size, chksize - size);
		VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
		return pointer;
	}
	else if (oldsize >= size)
	{
#ifdef MEMORY_CONTEXT_CHECKING
		Size		oldrequest = chunk->requested_size;
#ifdef RANDOMIZE_ALLOCATED_MEMORY
		if (size > oldrequest)
			randomize_mem((char *) pointer + oldrequest,
						  size - oldrequest);
#endif
		chunk->requested_size = size;
		if (size > oldrequest)
			VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + oldrequest,
										size - oldrequest);
		else
			VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size,
									   oldsize - size);
		if (size < oldsize)
			set_sentinel(pointer, size);
#else							
		VALGRIND_MAKE_MEM_NOACCESS(pointer, oldsize);
		VALGRIND_MAKE_MEM_DEFINED(pointer, size);
#endif
		VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
		return pointer;
	}
	else
	{
		AllocPointer newPointer;
		newPointer = AllocSetAlloc((MemoryContext) set, size);
		if (newPointer == NULL)
		{
			VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
			return NULL;
		}
		VALGRIND_MAKE_MEM_UNDEFINED(newPointer, size);
#ifdef MEMORY_CONTEXT_CHECKING
		oldsize = chunk->requested_size;
#else
		VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
#endif
		memcpy(newPointer, pointer, oldsize);
		AllocSetFree((MemoryContext) set, pointer);
		return newPointer;
	}
}
static void * AllocSetRealloc ( MemoryContext context , void * pointer , Size size ) { AllocSet set = ( AllocSet ) context ; AllocChunk chunk = AllocPointerGetChunk ( pointer ) ; Size oldsize ; VALGRIND_MAKE_MEM_DEFINED ( chunk , ALLOCCHUNK_PRIVATE_LEN ) ; oldsize = chunk -> size ; #ifdef MEMORY_CONTEXT_CHECKING if ( chunk -> requested_size < oldsize ) if ( ! sentinel_ok ( pointer , chunk -> requested_size ) ) elog ( WARNING , " " , set -> header . name , chunk ) ; #endif if ( oldsize > set -> allocChunkLimit ) { AllocBlock block = ( AllocBlock ) ( ( ( char * ) chunk ) - ALLOC_BLOCKHDRSZ ) ; Size chksize ; Size blksize ; Size oldblksize ; if ( block -> aset != set || block -> freeptr != block -> endptr || block -> freeptr != ( ( char * ) block ) + ( oldsize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ ) ) elog ( ERROR , " " , chunk ) ; chksize = Max ( size , set -> allocChunkLimit + 1 ) ; chksize = MAXALIGN ( chksize ) ; blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ ; oldblksize = block -> endptr - ( ( char * ) block ) ; block = ( AllocBlock ) realloc ( block , blksize ) ; if ( block == NULL ) { VALGRIND_MAKE_MEM_NOACCESS ( chunk , ALLOCCHUNK_PRIVATE_LEN ) ; return NULL ; } context -> mem_allocated -= oldblksize ; context -> mem_allocated += blksize ; block -> freeptr = block -> endptr = ( ( char * ) block ) + blksize ; chunk = ( AllocChunk ) ( ( ( char * ) block ) + ALLOC_BLOCKHDRSZ ) ; pointer = AllocChunkGetPointer ( chunk ) ; if ( block -> prev ) block -> prev -> next = block ; else set -> blocks = block ; if ( block -> next ) block -> next -> prev = block ; chunk -> size = chksize ; #ifdef MEMORY_CONTEXT_CHECKING #ifdef RANDOMIZE_ALLOCATED_MEMORY if ( size > chunk -> requested_size ) randomize_mem ( ( char * ) pointer + chunk -> requested_size , size - chunk -> requested_size ) ; #endif #ifdef USE_VALGRIND if ( oldsize > chunk -> requested_size ) VALGRIND_MAKE_MEM_UNDEFINED ( ( char * ) pointer + chunk -> requested_size , oldsize - chunk -> requested_size ) ; #endif chunk -> requested_size = size ; if ( size < chunk -> size ) set_sentinel ( pointer , size ) ; #else VALGRIND_MAKE_MEM_DEFINED ( pointer , oldsize ) ; #endif VALGRIND_MAKE_MEM_NOACCESS ( ( char * ) pointer + size , chksize - size ) ; VALGRIND_MAKE_MEM_NOACCESS ( chunk , ALLOCCHUNK_PRIVATE_LEN ) ; return pointer ; } else if ( oldsize >= size ) { #ifdef MEMORY_CONTEXT_CHECKING Size oldrequest = chunk -> requested_size ; #ifdef RANDOMIZE_ALLOCATED_MEMORY if ( size > oldrequest ) randomize_mem ( ( char * ) pointer + oldrequest , size - oldrequest ) ; #endif chunk -> requested_size = size ; if ( size > oldrequest ) VALGRIND_MAKE_MEM_UNDEFINED ( ( char * ) pointer + oldrequest , size - oldrequest ) ; else VALGRIND_MAKE_MEM_NOACCESS ( ( char * ) pointer + size , oldsize - size ) ; if ( size < oldsize ) set_sentinel ( pointer , size ) ; #else VALGRIND_MAKE_MEM_NOACCESS ( pointer , oldsize ) ; VALGRIND_MAKE_MEM_DEFINED ( pointer , size ) ; #endif VALGRIND_MAKE_MEM_NOACCESS ( chunk , ALLOCCHUNK_PRIVATE_LEN ) ; return pointer ; } else { AllocPointer newPointer ; newPointer = AllocSetAlloc ( ( MemoryContext ) set , size ) ; if ( newPointer == NULL ) { VALGRIND_MAKE_MEM_NOACCESS ( chunk , ALLOCCHUNK_PRIVATE_LEN ) ; return NULL ; } VALGRIND_MAKE_MEM_UNDEFINED ( newPointer , size ) ; #ifdef MEMORY_CONTEXT_CHECKING oldsize = chunk -> requested_size ; #else VALGRIND_MAKE_MEM_DEFINED ( pointer , oldsize ) ; #endif memcpy ( newPointer , pointer , oldsize ) ; AllocSetFree ( ( MemoryContext ) set , pointer ) ; return newPointer ; } }
AllocSetRealloc
              Returns new pointer to allocated memory of given size or NULL if
              request could not be completed; this memory is added to the set.
AllocSetRealloc Returns new pointer to allocated memory of given size or NULL if request could not be completed ; this memory is added to the set .
/* Allow access to private part of chunk header. */ /* Test for someone scribbling on unused space in chunk */ /*
		 * The chunk must have been allocated as a single-chunk block.  Use
		 * realloc() to make the containing block bigger, or smaller, with
		 * minimum space wastage.
		 */ /*
		 * 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.
		 */ /*
		 * Even if the new request is less than set->allocChunkLimit, we stick
		 * with the single-chunk block approach.  Therefore we need
		 * chunk->size to be bigger than set->allocChunkLimit, so we don't get
		 * confused about the chunk's status in future calls.
		 */ /* Do the realloc */ /* Disallow external access to private part of chunk header. */ /* updated separately, not to underflow when (oldblksize > blksize) */ /* Update pointers since block has likely been moved */ /* We can only fill the extra space if we know the prior request */ /*
		 * realloc() (or randomize_mem()) will have left any newly-allocated
		 * part UNDEFINED, but we may need to adjust trailing bytes from the
		 * old allocation.
		 */ /* set mark to catch clobber of "unused" space */ /* !MEMORY_CONTEXT_CHECKING */ /*
		 * We don't know how much of the old chunk size was the actual
		 * allocation; it could have been as small as one byte.  We have to be
		 * conservative and just mark the entire old portion DEFINED.
		 */ /* Ensure any padding bytes are marked NOACCESS. */ /* Disallow external access to private part of chunk header. */ /*
	 * Chunk sizes are aligned to power of 2 in AllocSetAlloc().  Maybe the
	 * allocated area already is >= the new size.  (In particular, we will
	 * fall out here if the requested size is a decrease.)
	 */ /* We can only fill the extra space if we know the prior request */ /*
		 * If this is an increase, mark any newly-available part UNDEFINED.
		 * Otherwise, mark the obsolete part NOACCESS.
		 */ /* set mark to catch clobber of "unused" space */ /* !MEMORY_CONTEXT_CHECKING */ /*
		 * We don't have the information to determine whether we're growing
		 * the old request or shrinking it, so we conservatively mark the
		 * entire new allocation DEFINED.
		 */ /* Disallow external access to private part of chunk header. */ /*
		 * Enlarge-a-small-chunk case.  We just do this by brute force, ie,
		 * allocate a new chunk and copy the data.  Since we know the existing
		 * data isn't huge, this won't involve any great memcpy expense, so
		 * it's not worth being smarter.  (At one time we tried to avoid
		 * memcpy when it was possible to enlarge the chunk in-place, but that
		 * turns out to misbehave unpleasantly for repeated cycles of
		 * palloc/repalloc/pfree: the eventually freed chunks go into the
		 * wrong freelist for the next initial palloc request, and so we leak
		 * memory indefinitely.  See pgsql-hackers archives for 2007-08-11.)
		 */ /* allocate new chunk */ /* leave immediately if request was not completed */ /* Disallow external access to private part of chunk header. */ /*
		 * AllocSetAlloc() may have returned a region that is still NOACCESS.
		 * Change it to UNDEFINED for the moment; memcpy() will then transfer
		 * definedness from the old allocation to the new.  If we know the old
		 * allocation, copy just that much.  Otherwise, make the entire old
		 * chunk defined to avoid errors as we copy the currently-NOACCESS
		 * trailing bytes.
		 */ /* transfer existing data (certain to fit) */ /* free old chunk */