Skip to content

Commit fa6af9b

Browse files
committed
localbuf: Fix dangerous coding pattern in GetLocalVictimBuffer()
If PinLocalBuffer() were to modify the buf_state, the buf_state in GetLocalVictimBuffer() would be out of date. Currently that does not happen, as PinLocalBuffer() only modifies the buf_state if adjust_usagecount=true and GetLocalVictimBuffer() passes false. However, it's easy to make this not the case anymore - it cost me a few hours to debug the consequences. The minimal fix would be to just refetch the buf_state after after calling PinLocalBuffer(), but the same danger exists in later parts of the function. Instead, declare buf_state in the narrower scopes and re-read the state in conditional branches. Besides being safer, it also fits well with an upcoming set of cleanup patches that move the contents of the conditional branches in GetLocalVictimBuffer() into helper functions. I "broke" this in 794f259. Arguably this should be backpatched, but as the relevant functions are not exported and there is no actual misbehaviour, I chose to not backpatch, at least for now. Reviewed-by: Melanie Plageman <melanieplageman@gmail.com> Discussion: https://postgr.es/m/CAAKRu_b9anbWzEs5AAF9WCvcEVmgz-1AkHSQ-CLLy-p7WHzvFw@mail.gmail.com
1 parent 5eabd91 commit fa6af9b

File tree

1 file changed

+5
-4
lines changed

1 file changed

+5
-4
lines changed

src/backend/storage/buffer/localbuf.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ GetLocalVictimBuffer(void)
178178
{
179179
int victim_bufid;
180180
int trycounter;
181-
uint32 buf_state;
182181
BufferDesc *bufHdr;
183182

184183
ResourceOwnerEnlarge(CurrentResourceOwner);
@@ -199,7 +198,7 @@ GetLocalVictimBuffer(void)
199198

200199
if (LocalRefCount[victim_bufid] == 0)
201200
{
202-
buf_state = pg_atomic_read_u32(&bufHdr->state);
201+
uint32 buf_state = pg_atomic_read_u32(&bufHdr->state);
203202

204203
if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0)
205204
{
@@ -233,8 +232,9 @@ GetLocalVictimBuffer(void)
233232
* this buffer is not referenced but it might still be dirty. if that's
234233
* the case, write it out before reusing it!
235234
*/
236-
if (buf_state & BM_DIRTY)
235+
if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY)
237236
{
237+
uint32 buf_state = pg_atomic_read_u32(&bufHdr->state);
238238
instr_time io_start;
239239
SMgrRelation oreln;
240240
Page localpage = (char *) LocalBufHdrGetBlock(bufHdr);
@@ -267,8 +267,9 @@ GetLocalVictimBuffer(void)
267267
/*
268268
* Remove the victim buffer from the hashtable and mark as invalid.
269269
*/
270-
if (buf_state & BM_TAG_VALID)
270+
if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID)
271271
{
272+
uint32 buf_state = pg_atomic_read_u32(&bufHdr->state);
272273
LocalBufferLookupEnt *hresult;
273274

274275
hresult = (LocalBufferLookupEnt *)

0 commit comments

Comments
 (0)