Check for relation length overrun soon enough.
authorTom Lane <[email protected]>
Thu, 9 Sep 2021 15:45:48 +0000 (11:45 -0400)
committerTom Lane <[email protected]>
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/[email protected]

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

index 236dc15f96e0b71b91e62d08ccd79a07a5b96bc2..bafe91ab0d69f71e0a3887d3889a4486526628a8 100644 (file)
@@ -726,7 +726,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 070660253c9ae15cfd3e7329507a38939a406aee..8c98a11435477e341d4100552d6d712d64e67b5b 100644 (file)
@@ -549,7 +549,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,