diff --git a/src/backend/access/transam/generic_xlog.c b/src/backend/access/transam/generic_xlog.c
index 072838a5e7a82eecd1fd6cec0d044b6fa621bbe5..e07bd836d2ef5c2163a62344abb6ae93d0089d92 100644
--- a/src/backend/access/transam/generic_xlog.c
+++ b/src/backend/access/transam/generic_xlog.c
@@ -338,17 +338,31 @@ GenericXLogFinish(GenericXLogState *state)
 		{
 			PageData   *pageData = &state->pages[i];
 			Page		page;
+			PageHeader	pageHeader;
 
 			if (BufferIsInvalid(pageData->buffer))
 				continue;
 
 			page = BufferGetPage(pageData->buffer, NULL, NULL,
 								 BGP_NO_SNAPSHOT_TEST);
+			pageHeader = (PageHeader) pageData->image;
 
 			if (pageData->fullImage)
 			{
-				/* A full page image does not require anything special */
-				memcpy(page, pageData->image, BLCKSZ);
+				/*
+				 * A full-page image does not require us to supply any xlog
+				 * data.  Just apply the image, being careful to zero the
+				 * "hole" between pd_lower and pd_upper in order to avoid
+				 * divergence between actual page state and what replay would
+				 * produce.
+				 */
+				memcpy(page, pageData->image, pageHeader->pd_lower);
+				memset(page + pageHeader->pd_lower, 0,
+					   pageHeader->pd_upper - pageHeader->pd_lower);
+				memcpy(page + pageHeader->pd_upper,
+					   pageData->image + pageHeader->pd_upper,
+					   BLCKSZ - pageHeader->pd_upper);
+
 				XLogRegisterBuffer(i, pageData->buffer,
 								   REGBUF_FORCE_IMAGE | REGBUF_STANDARD);
 			}
@@ -359,7 +373,15 @@ GenericXLogFinish(GenericXLogState *state)
 				 * associated with this page.
 				 */
 				computeDelta(pageData, page, (Page) pageData->image);
-				memcpy(page, pageData->image, BLCKSZ);
+
+				/* Apply the image, with zeroed "hole" as above */
+				memcpy(page, pageData->image, pageHeader->pd_lower);
+				memset(page + pageHeader->pd_lower, 0,
+					   pageHeader->pd_upper - pageHeader->pd_lower);
+				memcpy(page + pageHeader->pd_upper,
+					   pageData->image + pageHeader->pd_upper,
+					   BLCKSZ - pageHeader->pd_upper);
+
 				XLogRegisterBuffer(i, pageData->buffer, REGBUF_STANDARD);
 				XLogRegisterBufData(i, pageData->delta, pageData->deltaLen);
 			}
@@ -395,6 +417,7 @@ GenericXLogFinish(GenericXLogState *state)
 								 BGP_NO_SNAPSHOT_TEST),
 				   pageData->image,
 				   BLCKSZ);
+			/* We don't worry about zeroing the "hole" in this case */
 			MarkBufferDirty(pageData->buffer);
 		}
 		END_CRIT_SECTION();
@@ -473,6 +496,7 @@ generic_redo(XLogReaderState *record)
 		if (action == BLK_NEEDS_REDO)
 		{
 			Page		page;
+			PageHeader	pageHeader;
 			char	   *blockDelta;
 			Size		blockDeltaSize;
 
@@ -481,6 +505,16 @@ generic_redo(XLogReaderState *record)
 			blockDelta = XLogRecGetBlockData(record, block_id, &blockDeltaSize);
 			applyPageRedo(page, blockDelta, blockDeltaSize);
 
+			/*
+			 * Since the delta contains no information about what's in the
+			 * "hole" between pd_lower and pd_upper, set that to zero to
+			 * ensure we produce the same page state that application of the
+			 * logged action by GenericXLogFinish did.
+			 */
+			pageHeader = (PageHeader) page;
+			memset(page + pageHeader->pd_lower, 0,
+				   pageHeader->pd_upper - pageHeader->pd_lower);
+
 			PageSetLSN(page, lsn);
 			MarkBufferDirty(buffers[block_id]);
 		}