|  | 
| 103 | 103 | 
 | 
| 104 | 104 | #define ALLOC_BLOCKHDRSZ	MAXALIGN(sizeof(AllocBlockData)) | 
| 105 | 105 | #define ALLOC_CHUNKHDRSZ	sizeof(MemoryChunk) | 
|  | 106 | +#define FIRST_BLOCKHDRSZ	(MAXALIGN(sizeof(AllocSetContext)) + \ | 
|  | 107 | +							 ALLOC_BLOCKHDRSZ) | 
| 106 | 108 | 
 | 
| 107 | 109 | typedef struct AllocBlockData *AllocBlock;	/* forward reference */ | 
| 108 | 110 | 
 | 
| @@ -458,6 +460,21 @@ AllocSetContextCreateInternal(MemoryContext parent, | 
| 458 | 460 | 	 * we'd leak the header/initial block if we ereport in this stretch. | 
| 459 | 461 | 	 */ | 
| 460 | 462 | 
 | 
|  | 463 | +	/* Create a vpool associated with the context */ | 
|  | 464 | +	VALGRIND_CREATE_MEMPOOL(set, 0, false); | 
|  | 465 | + | 
|  | 466 | +	/* | 
|  | 467 | +	 * Create a vchunk covering both the AllocSetContext struct and the keeper | 
|  | 468 | +	 * block's header.  (Perhaps it would be more sensible for these to be two | 
|  | 469 | +	 * separate vchunks, but doing that seems to tickle bugs in some versions | 
|  | 470 | +	 * of Valgrind.)  We must have these vchunks, and also a vchunk for each | 
|  | 471 | +	 * subsequently-added block header, so that Valgrind considers the | 
|  | 472 | +	 * pointers within them while checking for leaked memory.  Note that | 
|  | 473 | +	 * Valgrind doesn't distinguish between these vchunks and those created by | 
|  | 474 | +	 * mcxt.c for the user-accessible-data chunks we allocate. | 
|  | 475 | +	 */ | 
|  | 476 | +	VALGRIND_MEMPOOL_ALLOC(set, set, FIRST_BLOCKHDRSZ); | 
|  | 477 | + | 
| 461 | 478 | 	/* Fill in the initial block's block header */ | 
| 462 | 479 | 	block = KeeperBlock(set); | 
| 463 | 480 | 	block->aset = set; | 
| @@ -585,13 +602,29 @@ AllocSetReset(MemoryContext context) | 
| 585 | 602 | #ifdef CLOBBER_FREED_MEMORY | 
| 586 | 603 | 			wipe_mem(block, block->freeptr - ((char *) block)); | 
| 587 | 604 | #endif | 
|  | 605 | + | 
|  | 606 | +			/* | 
|  | 607 | +			 * We need to free the block header's vchunk explicitly, although | 
|  | 608 | +			 * the user-data vchunks within will go away in the TRIM below. | 
|  | 609 | +			 * Otherwise Valgrind complains about leaked allocations. | 
|  | 610 | +			 */ | 
|  | 611 | +			VALGRIND_MEMPOOL_FREE(set, block); | 
|  | 612 | + | 
| 588 | 613 | 			free(block); | 
| 589 | 614 | 		} | 
| 590 | 615 | 		block = next; | 
| 591 | 616 | 	} | 
| 592 | 617 | 
 | 
| 593 | 618 | 	Assert(context->mem_allocated == keepersize); | 
| 594 | 619 | 
 | 
|  | 620 | +	/* | 
|  | 621 | +	 * Instruct Valgrind to throw away all the vchunks associated with this | 
|  | 622 | +	 * context, except for the one covering the AllocSetContext and | 
|  | 623 | +	 * keeper-block header.  This gets rid of the vchunks for whatever user | 
|  | 624 | +	 * data is getting discarded by the context reset. | 
|  | 625 | +	 */ | 
|  | 626 | +	VALGRIND_MEMPOOL_TRIM(set, set, FIRST_BLOCKHDRSZ); | 
|  | 627 | + | 
| 595 | 628 | 	/* Reset block size allocation sequence, too */ | 
| 596 | 629 | 	set->nextBlockSize = set->initBlockSize; | 
| 597 | 630 | } | 
| @@ -648,6 +681,9 @@ AllocSetDelete(MemoryContext context) | 
| 648 | 681 | 				freelist->first_free = (AllocSetContext *) oldset->header.nextchild; | 
| 649 | 682 | 				freelist->num_free--; | 
| 650 | 683 | 
 | 
|  | 684 | +				/* Destroy the context's vpool --- see notes below */ | 
|  | 685 | +				VALGRIND_DESTROY_MEMPOOL(oldset); | 
|  | 686 | + | 
| 651 | 687 | 				/* All that remains is to free the header/initial block */ | 
| 652 | 688 | 				free(oldset); | 
| 653 | 689 | 			} | 
| @@ -675,13 +711,24 @@ AllocSetDelete(MemoryContext context) | 
| 675 | 711 | #endif | 
| 676 | 712 | 
 | 
| 677 | 713 | 		if (!IsKeeperBlock(set, block)) | 
|  | 714 | +		{ | 
|  | 715 | +			/* As in AllocSetReset, free block-header vchunks explicitly */ | 
|  | 716 | +			VALGRIND_MEMPOOL_FREE(set, block); | 
| 678 | 717 | 			free(block); | 
|  | 718 | +		} | 
| 679 | 719 | 
 | 
| 680 | 720 | 		block = next; | 
| 681 | 721 | 	} | 
| 682 | 722 | 
 | 
| 683 | 723 | 	Assert(context->mem_allocated == keepersize); | 
| 684 | 724 | 
 | 
|  | 725 | +	/* | 
|  | 726 | +	 * Destroy the vpool.  We don't seem to need to explicitly free the | 
|  | 727 | +	 * initial block's header vchunk, nor any user-data vchunks that Valgrind | 
|  | 728 | +	 * still knows about; they'll all go away automatically. | 
|  | 729 | +	 */ | 
|  | 730 | +	VALGRIND_DESTROY_MEMPOOL(set); | 
|  | 731 | + | 
| 685 | 732 | 	/* Finally, free the context header, including the keeper block */ | 
| 686 | 733 | 	free(set); | 
| 687 | 734 | } | 
| @@ -716,6 +763,9 @@ AllocSetAllocLarge(MemoryContext context, Size size, int flags) | 
| 716 | 763 | 	if (block == NULL) | 
| 717 | 764 | 		return MemoryContextAllocationFailure(context, size, flags); | 
| 718 | 765 | 
 | 
|  | 766 | +	/* Make a vchunk covering the new block's header */ | 
|  | 767 | +	VALGRIND_MEMPOOL_ALLOC(set, block, ALLOC_BLOCKHDRSZ); | 
|  | 768 | + | 
| 719 | 769 | 	context->mem_allocated += blksize; | 
| 720 | 770 | 
 | 
| 721 | 771 | 	block->aset = set; | 
| @@ -922,6 +972,9 @@ AllocSetAllocFromNewBlock(MemoryContext context, Size size, int flags, | 
| 922 | 972 | 	if (block == NULL) | 
| 923 | 973 | 		return MemoryContextAllocationFailure(context, size, flags); | 
| 924 | 974 | 
 | 
|  | 975 | +	/* Make a vchunk covering the new block's header */ | 
|  | 976 | +	VALGRIND_MEMPOOL_ALLOC(set, block, ALLOC_BLOCKHDRSZ); | 
|  | 977 | + | 
| 925 | 978 | 	context->mem_allocated += blksize; | 
| 926 | 979 | 
 | 
| 927 | 980 | 	block->aset = set; | 
| @@ -1104,6 +1157,10 @@ AllocSetFree(void *pointer) | 
| 1104 | 1157 | #ifdef CLOBBER_FREED_MEMORY | 
| 1105 | 1158 | 		wipe_mem(block, block->freeptr - ((char *) block)); | 
| 1106 | 1159 | #endif | 
|  | 1160 | + | 
|  | 1161 | +		/* As in AllocSetReset, free block-header vchunks explicitly */ | 
|  | 1162 | +		VALGRIND_MEMPOOL_FREE(set, block); | 
|  | 1163 | + | 
| 1107 | 1164 | 		free(block); | 
| 1108 | 1165 | 	} | 
| 1109 | 1166 | 	else | 
| @@ -1184,6 +1241,7 @@ AllocSetRealloc(void *pointer, Size size, int flags) | 
| 1184 | 1241 | 		 * realloc() to make the containing block bigger, or smaller, with | 
| 1185 | 1242 | 		 * minimum space wastage. | 
| 1186 | 1243 | 		 */ | 
|  | 1244 | +		AllocBlock	newblock; | 
| 1187 | 1245 | 		Size		chksize; | 
| 1188 | 1246 | 		Size		blksize; | 
| 1189 | 1247 | 		Size		oldblksize; | 
| @@ -1223,14 +1281,21 @@ AllocSetRealloc(void *pointer, Size size, int flags) | 
| 1223 | 1281 | 		blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ; | 
| 1224 | 1282 | 		oldblksize = block->endptr - ((char *) block); | 
| 1225 | 1283 | 
 | 
| 1226 |  | -		block = (AllocBlock) realloc(block, blksize); | 
| 1227 |  | -		if (block == NULL) | 
|  | 1284 | +		newblock = (AllocBlock) realloc(block, blksize); | 
|  | 1285 | +		if (newblock == NULL) | 
| 1228 | 1286 | 		{ | 
| 1229 | 1287 | 			/* Disallow access to the chunk header. */ | 
| 1230 | 1288 | 			VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ); | 
| 1231 | 1289 | 			return MemoryContextAllocationFailure(&set->header, size, flags); | 
| 1232 | 1290 | 		} | 
| 1233 | 1291 | 
 | 
|  | 1292 | +		/* | 
|  | 1293 | +		 * Move the block-header vchunk explicitly.  (mcxt.c will take care of | 
|  | 1294 | +		 * moving the vchunk for the user data.) | 
|  | 1295 | +		 */ | 
|  | 1296 | +		VALGRIND_MEMPOOL_CHANGE(set, block, newblock, ALLOC_BLOCKHDRSZ); | 
|  | 1297 | +		block = newblock; | 
|  | 1298 | + | 
| 1234 | 1299 | 		/* updated separately, not to underflow when (oldblksize > blksize) */ | 
| 1235 | 1300 | 		set->header.mem_allocated -= oldblksize; | 
| 1236 | 1301 | 		set->header.mem_allocated += blksize; | 
| @@ -1294,7 +1359,7 @@ AllocSetRealloc(void *pointer, Size size, int flags) | 
| 1294 | 1359 | 		/* Ensure any padding bytes are marked NOACCESS. */ | 
| 1295 | 1360 | 		VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size, chksize - size); | 
| 1296 | 1361 | 
 | 
| 1297 |  | -		/* Disallow access to the chunk header . */ | 
|  | 1362 | +		/* Disallow access to the chunk header. */ | 
| 1298 | 1363 | 		VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ); | 
| 1299 | 1364 | 
 | 
| 1300 | 1365 | 		return pointer; | 
|  | 
0 commit comments