Add more sanity-checking to PageAddItem and PageIndexTupleDelete,
authorTom Lane <[email protected]>
Tue, 15 Jan 2002 22:14:17 +0000 (22:14 +0000)
committerTom Lane <[email protected]>
Tue, 15 Jan 2002 22:14:17 +0000 (22:14 +0000)
to prevent spreading of corruption when page header pointers are bad.
Merge PageZero into PageInit, since it was never used separately, and
remove separate memset calls used at most other PageInit call points.
Remove IndexPageCleanup, which wasn't used at all.

src/backend/access/gist/gist.c
src/backend/access/hash/hashpage.c
src/backend/access/heap/heapam.c
src/backend/access/nbtree/nbtpage.c
src/backend/access/rtree/rtree.c
src/backend/storage/page/bufpage.c
src/include/storage/bufpage.h

index 2431e1a3bdd587f45629a561c371a498ed6a3539..8062faa2691f89c82ac0cddea26efaaf70bc6be4 100644 (file)
@@ -1437,7 +1437,7 @@ GISTInitBuffer(Buffer b, uint32 f)
        pageSize = BufferGetPageSize(b);
 
        page = BufferGetPage(b);
-       MemSet(page, 0, (int) pageSize);
+
        PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
 
        opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
index 5643903ba4cf4f5b353156f0b346bbf3f47be033..f8d2b2f6f0fadb3636f81140b8f5bf73dc1297c6 100644 (file)
@@ -301,17 +301,7 @@ _hash_chgbufaccess(Relation rel,
 void
 _hash_pageinit(Page page, Size size)
 {
-       Assert(((PageHeader) page)->pd_lower == 0);
-       Assert(((PageHeader) page)->pd_upper == 0);
-       Assert(((PageHeader) page)->pd_special == 0);
-
-       /*
-        * Cargo-cult programming -- don't really need this to be zero, but
-        * creating new pages is an infrequent occurrence and it makes me feel
-        * good when I know they're empty.
-        */
-       MemSet(page, 0, size);
-
+       Assert(PageIsNew(page));
        PageInit(page, size, sizeof(HashPageOpaqueData));
 }
 
index a4c7d99c6219b1a734b12e62c2dba27bd76e94e7..ea93d0f628c46257751978c7f2f961464249b2f2 100644 (file)
@@ -2094,10 +2094,7 @@ heap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
                uint32          newlen;
 
                if (record->xl_info & XLOG_HEAP_INIT_PAGE)
-               {
                        PageInit(page, BufferGetPageSize(buffer), 0);
-                       PageZero(page);
-               }
 
                if (XLByteLE(lsn, PageGetLSN(page)))    /* changes are applied */
                {
@@ -2262,10 +2259,7 @@ newsame:;
                uint32          newlen;
 
                if (record->xl_info & XLOG_HEAP_INIT_PAGE)
-               {
                        PageInit(page, BufferGetPageSize(buffer), 0);
-                       PageZero(page);
-               }
 
                if (XLByteLE(lsn, PageGetLSN(page)))    /* changes are applied */
                {
index 21c1714eb39de744b42aa6ae91520907d130d8b2..3c0bcd33791ab31a96627fd4a9f0bc95821c1e94 100644 (file)
@@ -399,14 +399,6 @@ _bt_wrtnorelbuf(Relation rel, Buffer buf)
 void
 _bt_pageinit(Page page, Size size)
 {
-       /*
-        * Cargo_cult programming -- don't really need this to be zero, but
-        * creating new pages is an infrequent occurrence and it makes me feel
-        * good when I know they're empty.
-        */
-
-       MemSet(page, 0, size);
-
        PageInit(page, size, sizeof(BTPageOpaqueData));
        ((BTPageOpaque) PageGetSpecialPointer(page))->btpo_parent =
                InvalidBlockNumber;
index dd5717b92523743394d6d04f29e47ab8c71aba8c..5f5b826058e60fb1ff8e62a4e97b740ca18fedb3 100644 (file)
@@ -1107,7 +1107,7 @@ RTInitBuffer(Buffer b, uint32 f)
        pageSize = BufferGetPageSize(b);
 
        page = BufferGetPage(b);
-       MemSet(page, 0, (int) pageSize);
+
        PageInit(page, pageSize, sizeof(RTreePageOpaqueData));
 
        opaque = (RTreePageOpaque) PageGetSpecialPointer(page);
index 5487413e673a6d4dd2fb4298463bd9ee92f2c6ca..e7c72f67afb4401ea3dd056dd2ad72517d8876cf 100644 (file)
 #include "storage/bufpage.h"
 
 
-static void PageIndexTupleDeleteAdjustLinePointers(PageHeader phdr,
-                                                                          char *location, Size size);
-
-
 /* ----------------------------------------------------------------
  *                                             Page support functions
  * ----------------------------------------------------------------
@@ -44,24 +40,15 @@ PageInit(Page page, Size pageSize, Size specialSize)
        Assert(pageSize >
                   specialSize + sizeof(PageHeaderData) - sizeof(ItemIdData));
 
+       /* Make sure all fields of page are zero, as well as unused space */
+       MemSet(p, 0, pageSize);
+
        p->pd_lower = sizeof(PageHeaderData) - sizeof(ItemIdData);
        p->pd_upper = pageSize - specialSize;
        p->pd_special = pageSize - specialSize;
        PageSetPageSize(page, pageSize);
-
-       p->pd_lsn.xlogid = p->pd_lsn.xrecoff = 0;
-       p->pd_sui = 0;
 }
 
-/*
- * WAL needs in zero-ed page data content
- */
-void
-PageZero(Page page)
-{
-       MemSet((char *) page + ((PageHeader) page)->pd_lower, 0,
-               ((PageHeader) page)->pd_special - ((PageHeader) page)->pd_lower);
-}
 
 /* ----------------
  *             PageAddItem
@@ -86,10 +73,11 @@ PageAddItem(Page page,
                        OffsetNumber offsetNumber,
                        ItemIdFlags flags)
 {
+       PageHeader      phdr = (PageHeader) page;
        int                     i;
        Size            alignedSize;
-       Offset          lower;
-       Offset          upper;
+       int                     lower;
+       int                     upper;
        ItemId          itemId;
        OffsetNumber limit;
        bool            needshuffle = false;
@@ -97,6 +85,16 @@ PageAddItem(Page page,
 
        flags &= ~OverwritePageMode;
 
+       /*
+        * Be wary about corrupted page pointers
+        */
+       if (phdr->pd_lower < (sizeof(PageHeaderData) - sizeof(ItemIdData)) ||
+               phdr->pd_lower > phdr->pd_upper ||
+               phdr->pd_upper > phdr->pd_special ||
+               phdr->pd_special > BLCKSZ)
+               elog(ERROR, "PageAddItem: corrupted page pointers: lower = %u, upper = %u, special = %u",
+                        phdr->pd_lower, phdr->pd_upper, phdr->pd_special);
+
        /*
         * Find first unallocated offsetNumber
         */
@@ -114,7 +112,7 @@ PageAddItem(Page page,
                        }
                        if (offsetNumber < limit)
                        {
-                               itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1];
+                               itemId = &phdr->pd_linp[offsetNumber - 1];
                                if (((*itemId).lp_flags & LP_USED) ||
                                        ((*itemId).lp_len != 0))
                                {
@@ -138,7 +136,7 @@ PageAddItem(Page page,
                /* look for "recyclable" (unused & deallocated) ItemId */
                for (offsetNumber = 1; offsetNumber < limit; offsetNumber++)
                {
-                       itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1];
+                       itemId = &phdr->pd_linp[offsetNumber - 1];
                        if ((((*itemId).lp_flags & LP_USED) == 0) &&
                                ((*itemId).lp_len == 0))
                                break;
@@ -146,18 +144,21 @@ PageAddItem(Page page,
        }
 
        /*
-        * Compute new lower and upper pointers for page, see if it'll fit
+        * Compute new lower and upper pointers for page, see if it'll fit.
+        *
+        * Note: do arithmetic as signed ints, to avoid mistakes if, say,
+        * alignedSize > pd_upper.
         */
        if (offsetNumber > limit)
-               lower = (Offset) (((char *) (&((PageHeader) page)->pd_linp[offsetNumber])) - ((char *) page));
+               lower = (char *) (&phdr->pd_linp[offsetNumber]) - (char *) page;
        else if (offsetNumber == limit || needshuffle)
-               lower = ((PageHeader) page)->pd_lower + sizeof(ItemIdData);
+               lower = phdr->pd_lower + sizeof(ItemIdData);
        else
-               lower = ((PageHeader) page)->pd_lower;
+               lower = phdr->pd_lower;
 
        alignedSize = MAXALIGN(size);
 
-       upper = ((PageHeader) page)->pd_upper - alignedSize;
+       upper = (int) phdr->pd_upper - (int) alignedSize;
 
        if (lower > upper)
                return InvalidOffsetNumber;
@@ -169,24 +170,26 @@ PageAddItem(Page page,
        if (needshuffle)
        {
                /* shuffle ItemId's (Do the PageManager Shuffle...) */
-               for (i = (limit - 1); i >= offsetNumber; i--)
+               for (i = (int) limit - 1; i >= (int) offsetNumber; i--)
                {
                        ItemId          fromitemId,
                                                toitemId;
 
-                       fromitemId = &((PageHeader) page)->pd_linp[i - 1];
-                       toitemId = &((PageHeader) page)->pd_linp[i];
+                       fromitemId = &phdr->pd_linp[i - 1];
+                       toitemId = &phdr->pd_linp[i];
                        *toitemId = *fromitemId;
                }
        }
 
-       itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1];
+       itemId = &phdr->pd_linp[offsetNumber - 1];
        (*itemId).lp_off = upper;
        (*itemId).lp_len = size;
        (*itemId).lp_flags = flags;
+
        memmove((char *) page + upper, item, size);
-       ((PageHeader) page)->pd_lower = lower;
-       ((PageHeader) page)->pd_upper = upper;
+
+       phdr->pd_lower = (LocationIndex) lower;
+       phdr->pd_upper = (LocationIndex) upper;
 
        return offsetNumber;
 }
@@ -383,79 +386,76 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
 Size
 PageGetFreeSpace(Page page)
 {
-       Size            space;
+       int                     space;
 
-       space = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower;
+       /*
+        * Use signed arithmetic here so that we behave sensibly if
+        * pd_lower > pd_upper.
+        */
+       space = (int) ((PageHeader) page)->pd_upper -
+               (int) ((PageHeader) page)->pd_lower;
 
-       if (space < sizeof(ItemIdData))
+       if (space < (int) sizeof(ItemIdData))
                return 0;
        space -= sizeof(ItemIdData);    /* XXX not always appropriate */
 
-       return space;
+       return (Size) space;
 }
 
-/*
- * PageRepairFragmentation un-useful for index page cleanup because
- * of it doesn't remove line pointers. This routine could be more
- * effective but ... no time -:)
- */
-void
-IndexPageCleanup(Buffer buffer)
-{
-       Page            page = (Page) BufferGetPage(buffer);
-       ItemId          lp;
-       OffsetNumber maxoff;
-       OffsetNumber i;
-
-       maxoff = PageGetMaxOffsetNumber(page);
-       for (i = 0; i < maxoff; i++)
-       {
-               lp = ((PageHeader) page)->pd_linp + i;
-               if ((*lp).lp_flags & LP_DELETE) /* marked for deletion */
-               {
-                       PageIndexTupleDelete(page, i + 1);
-                       maxoff--;
-               }
-       }
-}
 
 /*
- *----------------------------------------------------------------
  * PageIndexTupleDelete
- *----------------------------------------------------------------
  *
- *             This routine does the work of removing a tuple from an index page.
+ * This routine does the work of removing a tuple from an index page.
+ *
+ * Unlike heap pages, we compact out the line pointer for the removed tuple.
  */
 void
 PageIndexTupleDelete(Page page, OffsetNumber offnum)
 {
-       PageHeader      phdr;
+       PageHeader      phdr = (PageHeader) page;
        char       *addr;
        ItemId          tup;
        Size            size;
-       char       *locn;
+       unsigned        offset;
        int                     nbytes;
        int                     offidx;
+       int                     nline,
+                               i;
+
+       /*
+        * As with PageRepairFragmentation, paranoia seems justified.
+        */
+       if (phdr->pd_lower < (sizeof(PageHeaderData) - sizeof(ItemIdData)) ||
+               phdr->pd_lower > phdr->pd_upper ||
+               phdr->pd_upper > phdr->pd_special ||
+               phdr->pd_special > BLCKSZ)
+               elog(ERROR, "PageIndexTupleDelete: corrupted page pointers: lower = %u, upper = %u, special = %u",
+                        phdr->pd_lower, phdr->pd_upper, phdr->pd_special);
 
-       phdr = (PageHeader) page;
+       nline = PageGetMaxOffsetNumber(page);
+       if ((int) offnum <= 0 || (int) offnum > nline)
+               elog(ERROR, "PageIndexTupleDelete: bad offnum %u", offnum);
 
        /* change offset number to offset index */
        offidx = offnum - 1;
 
        tup = PageGetItemId(page, offnum);
        size = ItemIdGetLength(tup);
-       size = MAXALIGN(size);
+       offset = ItemIdGetOffset(tup);
 
-       /* location of deleted tuple data */
-       locn = (char *) (page + ItemIdGetOffset(tup));
+       if (offset < phdr->pd_upper || (offset + size) > phdr->pd_special ||
+               offset != MAXALIGN(offset) || size != MAXALIGN(size))
+               elog(ERROR, "PageIndexTupleDelete: corrupted item pointer: offset = %u size = %u",
+                        offset, size);
 
        /*
         * First, we want to get rid of the pd_linp entry for the index tuple.
         * We copy all subsequent linp's back one slot in the array.
         */
-
        nbytes = phdr->pd_lower -
                ((char *) &phdr->pd_linp[offidx + 1] - (char *) phdr);
+
        memmove((char *) &(phdr->pd_linp[offidx]),
                        (char *) &(phdr->pd_linp[offidx + 1]),
                        nbytes);
@@ -470,52 +470,28 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum)
         */
 
        /* beginning of tuple space */
-       addr = (char *) (page + phdr->pd_upper);
+       addr = (char *) page + phdr->pd_upper;
 
-       if (locn != addr)
-               memmove(addr + size, addr, (int) (locn - addr));
+       if (offset > phdr->pd_upper)
+               memmove(addr + size, addr, (int) (offset - phdr->pd_upper));
 
        /* adjust free space boundary pointers */
        phdr->pd_upper += size;
        phdr->pd_lower -= sizeof(ItemIdData);
 
-       /* finally, we need to adjust the linp entries that remain */
+       /*
+        * Finally, we need to adjust the linp entries that remain.
+        *
+        * Anything that used to be before the deleted tuple's data was moved
+        * forward by the size of the deleted tuple.
+        */
        if (!PageIsEmpty(page))
-               PageIndexTupleDeleteAdjustLinePointers(phdr, locn, size);
-}
-
-/*
- *----------------------------------------------------------------
- * PageIndexTupleDeleteAdjustLinePointers
- *----------------------------------------------------------------
- *
- *             Once the line pointers and tuple data have been shifted around
- *             on the page, we need to go down the line pointer vector and
- *             adjust pointers to reflect new locations.  Anything that used
- *             to be before the deleted tuple's data was moved forward by the
- *             size of the deleted tuple.
- *
- *             This routine does the work of adjusting the line pointers.
- *             Location is where the tuple data used to lie; size is how
- *             much space it occupied.  We assume that size has been aligned
- *             as required by the time we get here.
- *
- *             This routine should never be called on an empty page.
- */
-static void
-PageIndexTupleDeleteAdjustLinePointers(PageHeader phdr,
-                                                                          char *location,
-                                                                          Size size)
-{
-       int                     i;
-       unsigned        offset;
-
-       /* location is an index into the page... */
-       offset = (unsigned) (location - (char *) phdr);
-
-       for (i = PageGetMaxOffsetNumber((Page) phdr) - 1; i >= 0; i--)
        {
-               if (phdr->pd_linp[i].lp_off <= offset)
-                       phdr->pd_linp[i].lp_off += size;
+               nline--;                                /* there's one less than when we started */
+               for (i = nline; --i >= 0; )
+               {
+                       if (phdr->pd_linp[i].lp_off <= offset)
+                               phdr->pd_linp[i].lp_off += size;
+               }
        }
 }
index 8b77042bf658e7c8069f3ba9dfe604352b77d2e5..e66d9f02dbe13a31cd26850913312dcfc5f9d886 100644 (file)
@@ -310,7 +310,6 @@ typedef enum
  */
 
 extern void PageInit(Page page, Size pageSize, Size specialSize);
-extern void PageZero(Page page);
 extern OffsetNumber PageAddItem(Page page, Item item, Size size,
                        OffsetNumber offsetNumber, ItemIdFlags flags);
 extern Page PageGetTempPage(Page page, Size specialSize);
@@ -318,6 +317,5 @@ extern void PageRestoreTempPage(Page tempPage, Page oldPage);
 extern int     PageRepairFragmentation(Page page, OffsetNumber *unused);
 extern Size PageGetFreeSpace(Page page);
 extern void PageIndexTupleDelete(Page page, OffsetNumber offset);
-extern void IndexPageCleanup(Buffer buffer);
 
 #endif   /* BUFPAGE_H */