Commit aa00e613 authored by Tom Lane's avatar Tom Lane

Add more sanity-checking to PageAddItem and PageIndexTupleDelete,

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.
parent 685a66cd
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.86 2001/11/05 17:46:23 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.87 2002/01/15 22:14:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1437,7 +1437,7 @@ GISTInitBuffer(Buffer b, uint32 f) ...@@ -1437,7 +1437,7 @@ GISTInitBuffer(Buffer b, uint32 f)
pageSize = BufferGetPageSize(b); pageSize = BufferGetPageSize(b);
page = BufferGetPage(b); page = BufferGetPage(b);
MemSet(page, 0, (int) pageSize);
PageInit(page, pageSize, sizeof(GISTPageOpaqueData)); PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
opaque = (GISTPageOpaque) PageGetSpecialPointer(page); opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.33 2001/10/25 05:49:21 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.34 2002/01/15 22:14:16 tgl Exp $
* *
* NOTES * NOTES
* Postgres hash pages look like ordinary relation pages. The opaque * Postgres hash pages look like ordinary relation pages. The opaque
...@@ -301,17 +301,7 @@ _hash_chgbufaccess(Relation rel, ...@@ -301,17 +301,7 @@ _hash_chgbufaccess(Relation rel,
void void
_hash_pageinit(Page page, Size size) _hash_pageinit(Page page, Size size)
{ {
Assert(((PageHeader) page)->pd_lower == 0); Assert(PageIsNew(page));
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);
PageInit(page, size, sizeof(HashPageOpaqueData)); PageInit(page, size, sizeof(HashPageOpaqueData));
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.128 2001/11/05 17:46:23 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.129 2002/01/15 22:14:17 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -2094,10 +2094,7 @@ heap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record) ...@@ -2094,10 +2094,7 @@ heap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
uint32 newlen; uint32 newlen;
if (record->xl_info & XLOG_HEAP_INIT_PAGE) if (record->xl_info & XLOG_HEAP_INIT_PAGE)
{
PageInit(page, BufferGetPageSize(buffer), 0); PageInit(page, BufferGetPageSize(buffer), 0);
PageZero(page);
}
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{ {
...@@ -2262,10 +2259,7 @@ newsame:; ...@@ -2262,10 +2259,7 @@ newsame:;
uint32 newlen; uint32 newlen;
if (record->xl_info & XLOG_HEAP_INIT_PAGE) if (record->xl_info & XLOG_HEAP_INIT_PAGE)
{
PageInit(page, BufferGetPageSize(buffer), 0); PageInit(page, BufferGetPageSize(buffer), 0);
PageZero(page);
}
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{ {
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.54 2001/10/25 05:49:21 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.55 2002/01/15 22:14:17 tgl Exp $
* *
* NOTES * NOTES
* Postgres btree pages look like ordinary relation pages. The opaque * Postgres btree pages look like ordinary relation pages. The opaque
...@@ -399,14 +399,6 @@ _bt_wrtnorelbuf(Relation rel, Buffer buf) ...@@ -399,14 +399,6 @@ _bt_wrtnorelbuf(Relation rel, Buffer buf)
void void
_bt_pageinit(Page page, Size size) _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)); PageInit(page, size, sizeof(BTPageOpaqueData));
((BTPageOpaque) PageGetSpecialPointer(page))->btpo_parent = ((BTPageOpaque) PageGetSpecialPointer(page))->btpo_parent =
InvalidBlockNumber; InvalidBlockNumber;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.68 2001/11/05 17:46:24 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.69 2002/01/15 22:14:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1107,7 +1107,7 @@ RTInitBuffer(Buffer b, uint32 f) ...@@ -1107,7 +1107,7 @@ RTInitBuffer(Buffer b, uint32 f)
pageSize = BufferGetPageSize(b); pageSize = BufferGetPageSize(b);
page = BufferGetPage(b); page = BufferGetPage(b);
MemSet(page, 0, (int) pageSize);
PageInit(page, pageSize, sizeof(RTreePageOpaqueData)); PageInit(page, pageSize, sizeof(RTreePageOpaqueData));
opaque = (RTreePageOpaque) PageGetSpecialPointer(page); opaque = (RTreePageOpaque) PageGetSpecialPointer(page);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.41 2001/11/08 04:05:13 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.42 2002/01/15 22:14:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,10 +20,6 @@ ...@@ -20,10 +20,6 @@
#include "storage/bufpage.h" #include "storage/bufpage.h"
static void PageIndexTupleDeleteAdjustLinePointers(PageHeader phdr,
char *location, Size size);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* Page support functions * Page support functions
* ---------------------------------------------------------------- * ----------------------------------------------------------------
...@@ -44,24 +40,15 @@ PageInit(Page page, Size pageSize, Size specialSize) ...@@ -44,24 +40,15 @@ PageInit(Page page, Size pageSize, Size specialSize)
Assert(pageSize > Assert(pageSize >
specialSize + sizeof(PageHeaderData) - sizeof(ItemIdData)); 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_lower = sizeof(PageHeaderData) - sizeof(ItemIdData);
p->pd_upper = pageSize - specialSize; p->pd_upper = pageSize - specialSize;
p->pd_special = pageSize - specialSize; p->pd_special = pageSize - specialSize;
PageSetPageSize(page, pageSize); 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 * PageAddItem
...@@ -86,10 +73,11 @@ PageAddItem(Page page, ...@@ -86,10 +73,11 @@ PageAddItem(Page page,
OffsetNumber offsetNumber, OffsetNumber offsetNumber,
ItemIdFlags flags) ItemIdFlags flags)
{ {
PageHeader phdr = (PageHeader) page;
int i; int i;
Size alignedSize; Size alignedSize;
Offset lower; int lower;
Offset upper; int upper;
ItemId itemId; ItemId itemId;
OffsetNumber limit; OffsetNumber limit;
bool needshuffle = false; bool needshuffle = false;
...@@ -97,6 +85,16 @@ PageAddItem(Page page, ...@@ -97,6 +85,16 @@ PageAddItem(Page page,
flags &= ~OverwritePageMode; 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 * Find first unallocated offsetNumber
*/ */
...@@ -114,7 +112,7 @@ PageAddItem(Page page, ...@@ -114,7 +112,7 @@ PageAddItem(Page page,
} }
if (offsetNumber < limit) if (offsetNumber < limit)
{ {
itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1]; itemId = &phdr->pd_linp[offsetNumber - 1];
if (((*itemId).lp_flags & LP_USED) || if (((*itemId).lp_flags & LP_USED) ||
((*itemId).lp_len != 0)) ((*itemId).lp_len != 0))
{ {
...@@ -138,7 +136,7 @@ PageAddItem(Page page, ...@@ -138,7 +136,7 @@ PageAddItem(Page page,
/* look for "recyclable" (unused & deallocated) ItemId */ /* look for "recyclable" (unused & deallocated) ItemId */
for (offsetNumber = 1; offsetNumber < limit; offsetNumber++) 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) && if ((((*itemId).lp_flags & LP_USED) == 0) &&
((*itemId).lp_len == 0)) ((*itemId).lp_len == 0))
break; break;
...@@ -146,18 +144,21 @@ PageAddItem(Page page, ...@@ -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) 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) else if (offsetNumber == limit || needshuffle)
lower = ((PageHeader) page)->pd_lower + sizeof(ItemIdData); lower = phdr->pd_lower + sizeof(ItemIdData);
else else
lower = ((PageHeader) page)->pd_lower; lower = phdr->pd_lower;
alignedSize = MAXALIGN(size); alignedSize = MAXALIGN(size);
upper = ((PageHeader) page)->pd_upper - alignedSize; upper = (int) phdr->pd_upper - (int) alignedSize;
if (lower > upper) if (lower > upper)
return InvalidOffsetNumber; return InvalidOffsetNumber;
...@@ -169,24 +170,26 @@ PageAddItem(Page page, ...@@ -169,24 +170,26 @@ PageAddItem(Page page,
if (needshuffle) if (needshuffle)
{ {
/* shuffle ItemId's (Do the PageManager Shuffle...) */ /* 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, ItemId fromitemId,
toitemId; toitemId;
fromitemId = &((PageHeader) page)->pd_linp[i - 1]; fromitemId = &phdr->pd_linp[i - 1];
toitemId = &((PageHeader) page)->pd_linp[i]; toitemId = &phdr->pd_linp[i];
*toitemId = *fromitemId; *toitemId = *fromitemId;
} }
} }
itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1]; itemId = &phdr->pd_linp[offsetNumber - 1];
(*itemId).lp_off = upper; (*itemId).lp_off = upper;
(*itemId).lp_len = size; (*itemId).lp_len = size;
(*itemId).lp_flags = flags; (*itemId).lp_flags = flags;
memmove((char *) page + upper, item, size); 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; return offsetNumber;
} }
...@@ -383,79 +386,76 @@ PageRepairFragmentation(Page page, OffsetNumber *unused) ...@@ -383,79 +386,76 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
Size Size
PageGetFreeSpace(Page page) 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; return 0;
space -= sizeof(ItemIdData); /* XXX not always appropriate */ 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 * 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 void
PageIndexTupleDelete(Page page, OffsetNumber offnum) PageIndexTupleDelete(Page page, OffsetNumber offnum)
{ {
PageHeader phdr; PageHeader phdr = (PageHeader) page;
char *addr; char *addr;
ItemId tup; ItemId tup;
Size size; Size size;
char *locn; unsigned offset;
int nbytes; int nbytes;
int offidx; 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 */ /* change offset number to offset index */
offidx = offnum - 1; offidx = offnum - 1;
tup = PageGetItemId(page, offnum); tup = PageGetItemId(page, offnum);
size = ItemIdGetLength(tup); size = ItemIdGetLength(tup);
size = MAXALIGN(size); offset = ItemIdGetOffset(tup);
/* location of deleted tuple data */ if (offset < phdr->pd_upper || (offset + size) > phdr->pd_special ||
locn = (char *) (page + ItemIdGetOffset(tup)); 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. * 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. * We copy all subsequent linp's back one slot in the array.
*/ */
nbytes = phdr->pd_lower - nbytes = phdr->pd_lower -
((char *) &phdr->pd_linp[offidx + 1] - (char *) phdr); ((char *) &phdr->pd_linp[offidx + 1] - (char *) phdr);
memmove((char *) &(phdr->pd_linp[offidx]), memmove((char *) &(phdr->pd_linp[offidx]),
(char *) &(phdr->pd_linp[offidx + 1]), (char *) &(phdr->pd_linp[offidx + 1]),
nbytes); nbytes);
...@@ -470,52 +470,28 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum) ...@@ -470,52 +470,28 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum)
*/ */
/* beginning of tuple space */ /* beginning of tuple space */
addr = (char *) (page + phdr->pd_upper); addr = (char *) page + phdr->pd_upper;
if (locn != addr) if (offset > phdr->pd_upper)
memmove(addr + size, addr, (int) (locn - addr)); memmove(addr + size, addr, (int) (offset - phdr->pd_upper));
/* adjust free space boundary pointers */ /* adjust free space boundary pointers */
phdr->pd_upper += size; phdr->pd_upper += size;
phdr->pd_lower -= sizeof(ItemIdData); 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)) 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) nline--; /* there's one less than when we started */
phdr->pd_linp[i].lp_off += size; for (i = nline; --i >= 0; )
{
if (phdr->pd_linp[i].lp_off <= offset)
phdr->pd_linp[i].lp_off += size;
}
} }
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: bufpage.h,v 1.46 2001/11/05 17:46:35 momjian Exp $ * $Id: bufpage.h,v 1.47 2002/01/15 22:14:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -310,7 +310,6 @@ typedef enum ...@@ -310,7 +310,6 @@ typedef enum
*/ */
extern void PageInit(Page page, Size pageSize, Size specialSize); extern void PageInit(Page page, Size pageSize, Size specialSize);
extern void PageZero(Page page);
extern OffsetNumber PageAddItem(Page page, Item item, Size size, extern OffsetNumber PageAddItem(Page page, Item item, Size size,
OffsetNumber offsetNumber, ItemIdFlags flags); OffsetNumber offsetNumber, ItemIdFlags flags);
extern Page PageGetTempPage(Page page, Size specialSize); extern Page PageGetTempPage(Page page, Size specialSize);
...@@ -318,6 +317,5 @@ extern void PageRestoreTempPage(Page tempPage, Page oldPage); ...@@ -318,6 +317,5 @@ extern void PageRestoreTempPage(Page tempPage, Page oldPage);
extern int PageRepairFragmentation(Page page, OffsetNumber *unused); extern int PageRepairFragmentation(Page page, OffsetNumber *unused);
extern Size PageGetFreeSpace(Page page); extern Size PageGetFreeSpace(Page page);
extern void PageIndexTupleDelete(Page page, OffsetNumber offset); extern void PageIndexTupleDelete(Page page, OffsetNumber offset);
extern void IndexPageCleanup(Buffer buffer);
#endif /* BUFPAGE_H */ #endif /* BUFPAGE_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment