Check for relation length overrun soon enough.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 9 Sep 2021 15:45:48 +0000 (11:45 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 9 Sep 2021 15:45:48 +0000 (11:45 -0400)
We don't allow relations to exceed 2^32-1 blocks, because block
numbers are 32 bits and the last possible block number is reserved
to mean InvalidBlockNumber.  There is a check for this in mdextend,
but that's really way too late, because the smgr API requires us to
create a buffer for the block-to-be-added, and we do not want to
have any buffer with blocknum InvalidBlockNumber.  (Such a case
can trigger assertions in bufmgr.c, plus I think it might confuse
ReadBuffer's logic for data-past-EOF later on.)  So put the check
into ReadBuffer.

Per report from Christoph Berg.  It's been like this forever,
so back-patch to all supported branches.

Discussion: https://postgr.es/m/YTn1iTkUYBZfcODk@msg.credativ.de

src/backend/storage/buffer/bufmgr.c
src/backend/storage/smgr/md.c

index bc1753ae916068cdf9e9d690a0f57b22b6c0b63d..e88e4e918b0951b263852a0aaf2e7d0584b15e65 100644 (file)
@@ -824,7 +824,16 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
 
    /* Substitute proper block number if caller asked for P_NEW */
    if (isExtend)
+   {
        blockNum = smgrnblocks(smgr, forkNum);
+       /* Fail if relation is already at maximum possible length */
+       if (blockNum == P_NEW)
+           ereport(ERROR,
+                   (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                    errmsg("cannot extend relation %s beyond %u blocks",
+                           relpath(smgr->smgr_rnode, forkNum),
+                           P_NEW)));
+   }
 
    if (isLocalBuf)
    {
index 1e12cfad8e855ab4e3dd56b0947a9dacf2c6ba67..b4bca7eed6fe437199b12a31986d35268875c58a 100644 (file)
@@ -426,7 +426,8 @@ mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
    /*
     * If a relation manages to grow to 2^32-1 blocks, refuse to extend it any
     * more --- we mustn't create a block whose number actually is
-    * InvalidBlockNumber.
+    * InvalidBlockNumber.  (Note that this failure should be unreachable
+    * because of upstream checks in bufmgr.c.)
     */
    if (blocknum == InvalidBlockNumber)
        ereport(ERROR,