Hi, On 2023-04-04 11:55:01 -0700, Andres Freund wrote: > Look at: > > static void > fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum) > { > Buffer buf; > Page page; > sequence_magic *sm; > OffsetNumber offnum; > > /* Initialize first page of relation with special magic number */ > > buf = ReadBufferExtended(rel, forkNum, P_NEW, RBM_NORMAL, NULL); > Assert(BufferGetBlockNumber(buf) == 0); > > page = BufferGetPage(buf); > > PageInit(page, BufferGetPageSize(buf), sizeof(sequence_magic)); > sm = (sequence_magic *) PageGetSpecialPointer(page); > sm->magic = SEQ_MAGIC; > > /* Now insert sequence tuple */ > > LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); > > > Clearly we are modifying the page (via PageInit()), without holding a buffer > lock, which is only acquired subsequently. > > It's clearly unlikely to cause bad consequences - the sequence doesn't yet > really exist, and we haven't seen any reports of a problem - but it doesn't > seem quite impossible that it would cause problems. > > As far as I can tell, this goes back to the initial addition of the sequence > code, in e8647c45d66a - I'm too lazy to figure out whether it possibly wasn't > a problem in 1997 for some reason.
Robert suggested to add an assertion to PageInit() to defend against such omissions. I quickly hacked one together. The assertion immediately found the issue here, but no other currently existing ones. I'm planning to push a fix for this to HEAD. Given that the risk seems low and the issue is so longstanding, it doesn't seem quite worth backpatching? FWIW, the assertion I used is: if (page >= BufferBlocks && page <= BufferBlocks + BLCKSZ * NBuffers) { Buffer buffer = (page - BufferBlocks) / BLCKSZ + 1; BufferDesc *buf = GetBufferDescriptor(buffer - 1); Assert(LWLockHeldByMeInMode(BufferDescriptorGetContentLock(buf), LW_EXCLUSIVE)); } If there's interest in having such an assertion permenantly, it clearly can't live in bufpage.c. I have a bit of a hard time coming up with a good name. Any suggestions? Greetings, Andres Freund