Skip to content

Commit 3f968b9

Browse files
committed
Fix ReadRecentBuffer for local buffers.
It incorrectly used GetBufferDescriptor instead of GetLocalBufferDescriptor, causing it to not find the correct buffer in most cases, and performing an out-of-bounds memory read in the corner case that temp_buffers > shared_buffers. It also bumped the usage-count on the buffer, even if it was previously pinned. That won't lead to crashes or incorrect results, but it's different from what the shared-buffer case does, and different from the usual code in LocalBufferAlloc. Fix that too, and make the code ordering match LocalBufferAlloc() more closely, so that it's easier to verify that it's doing the same thing. Currently, ReadRecentBuffer() is only used with non-temp relations, in WAL redo, so the broken code is currently dead code. However, it could be used by extensions. Backpatch-through: 14 Discussion: https://www.postgresql.org/message-id/2d74b46f-27c9-fb31-7f99-327a87184cc0%40iki.fi Reviewed-by: Thomas Munro, Zhang Mingli, Richard Guo
1 parent 31d5354 commit 3f968b9

File tree

1 file changed

+16
-6
lines changed

1 file changed

+16
-6
lines changed

src/backend/storage/buffer/bufmgr.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -634,18 +634,28 @@ ReadRecentBuffer(RelFileNode rnode, ForkNumber forkNum, BlockNumber blockNum,
634634

635635
if (BufferIsLocal(recent_buffer))
636636
{
637-
bufHdr = GetBufferDescriptor(-recent_buffer - 1);
637+
int b = -recent_buffer - 1;
638+
639+
bufHdr = GetLocalBufferDescriptor(b);
638640
buf_state = pg_atomic_read_u32(&bufHdr->state);
639641

640642
/* Is it still valid and holding the right tag? */
641643
if ((buf_state & BM_VALID) && BUFFERTAGS_EQUAL(tag, bufHdr->tag))
642644
{
643-
/* Bump local buffer's ref and usage counts. */
645+
/*
646+
* Bump buffer's ref and usage counts. This is equivalent of
647+
* PinBuffer for a shared buffer.
648+
*/
649+
if (LocalRefCount[b] == 0)
650+
{
651+
if (BUF_STATE_GET_USAGECOUNT(buf_state) < BM_MAX_USAGE_COUNT)
652+
{
653+
buf_state += BUF_USAGECOUNT_ONE;
654+
pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
655+
}
656+
}
657+
LocalRefCount[b]++;
644658
ResourceOwnerRememberBuffer(CurrentResourceOwner, recent_buffer);
645-
LocalRefCount[-recent_buffer - 1]++;
646-
if (BUF_STATE_GET_USAGECOUNT(buf_state) < BM_MAX_USAGE_COUNT)
647-
pg_atomic_write_u32(&bufHdr->state,
648-
buf_state + BUF_USAGECOUNT_ONE);
649659

650660
return true;
651661
}

0 commit comments

Comments
 (0)