diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2014-06-05 12:55:35 +0300 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2014-06-05 12:55:35 +0300 |
commit | 8776faa81cb651322b8993422bdd4633f1f6a487 (patch) | |
tree | 6640167704ea17b559704c800bcf36a9cfd05a22 /src/backend/access/spgist/spgxlog.c | |
parent | d4d48a5edd9eb28a7f2ee2e4cbe20d984274982e (diff) | |
download | postgresql-8776faa81cb651322b8993422bdd4633f1f6a487.tar.gz postgresql-8776faa81cb651322b8993422bdd4633f1f6a487.zip |
Adjust SP-GiST WAL record formats to reduce alignment padding.
The way the code was written, the padding was copied from uninitialized
memory areas.. Because the structs are local variables in the code where
the WAL records are constructed, making them larger and zeroing the padding
bytes would not make the code very pretty, so rather than fixing this
directly by zeroing out the padding bytes, it seems more clear to not try to
align the tuples in the WAL records. The redo functions are taught to copy
the tuple header to a local variable to avoid unaligned access.
Stable-branches have the same problem, but we can't change the WAL format
there, so fix in master only. Reading a few random extra bytes at the stack
is harmless in practice, so it's not worth crafting a different
back-patchable fix.
Per reports from Kevin Grittner and Andres Freund, using clang static
analyzer and Valgrind, respectively.
Diffstat (limited to 'src/backend/access/spgist/spgxlog.c')
-rw-r--r-- | src/backend/access/spgist/spgxlog.c | 116 |
1 files changed, 71 insertions, 45 deletions
diff --git a/src/backend/access/spgist/spgxlog.c b/src/backend/access/spgist/spgxlog.c index cc0184d174d..e4f7fbb53a5 100644 --- a/src/backend/access/spgist/spgxlog.c +++ b/src/backend/access/spgist/spgxlog.c @@ -109,13 +109,15 @@ spgRedoAddLeaf(XLogRecPtr lsn, XLogRecord *record) { char *ptr = XLogRecGetData(record); spgxlogAddLeaf *xldata = (spgxlogAddLeaf *) ptr; - SpGistLeafTuple leafTuple; + char *leafTuple; + SpGistLeafTupleData leafTupleHdr; Buffer buffer; Page page; - /* we assume this is adequately aligned */ ptr += sizeof(spgxlogAddLeaf); - leafTuple = (SpGistLeafTuple) ptr; + leafTuple = ptr; + /* the leaf tuple is unaligned, so make a copy to access its header */ + memcpy(&leafTupleHdr, leafTuple, sizeof(SpGistLeafTupleData)); /* * In normal operation we would have both current and parent pages locked @@ -142,7 +144,7 @@ spgRedoAddLeaf(XLogRecPtr lsn, XLogRecord *record) if (xldata->offnumLeaf != xldata->offnumHeadLeaf) { /* normal cases, tuple was added by SpGistPageAddNewItem */ - addOrReplaceTuple(page, (Item) leafTuple, leafTuple->size, + addOrReplaceTuple(page, (Item) leafTuple, leafTupleHdr.size, xldata->offnumLeaf); /* update head tuple's chain link if needed */ @@ -152,7 +154,7 @@ spgRedoAddLeaf(XLogRecPtr lsn, XLogRecord *record) head = (SpGistLeafTuple) PageGetItem(page, PageGetItemId(page, xldata->offnumHeadLeaf)); - Assert(head->nextOffset == leafTuple->nextOffset); + Assert(head->nextOffset == leafTupleHdr.nextOffset); head->nextOffset = xldata->offnumLeaf; } } @@ -161,10 +163,10 @@ spgRedoAddLeaf(XLogRecPtr lsn, XLogRecord *record) /* replacing a DEAD tuple */ PageIndexTupleDelete(page, xldata->offnumLeaf); if (PageAddItem(page, - (Item) leafTuple, leafTuple->size, + (Item) leafTuple, leafTupleHdr.size, xldata->offnumLeaf, false, false) != xldata->offnumLeaf) elog(ERROR, "failed to add item of size %u to SPGiST index page", - leafTuple->size); + leafTupleHdr.size); } PageSetLSN(page, lsn); @@ -217,11 +219,11 @@ spgRedoMoveLeafs(XLogRecPtr lsn, XLogRecord *record) nInsert = xldata->replaceDead ? 1 : xldata->nMoves + 1; - ptr += MAXALIGN(sizeof(spgxlogMoveLeafs)); + ptr += SizeOfSpgxlogMoveLeafs; toDelete = (OffsetNumber *) ptr; - ptr += MAXALIGN(sizeof(OffsetNumber) * xldata->nMoves); + ptr += sizeof(OffsetNumber) * xldata->nMoves; toInsert = (OffsetNumber *) ptr; - ptr += MAXALIGN(sizeof(OffsetNumber) * nInsert); + ptr += sizeof(OffsetNumber) * nInsert; /* now ptr points to the list of leaf tuples */ @@ -252,10 +254,20 @@ spgRedoMoveLeafs(XLogRecPtr lsn, XLogRecord *record) for (i = 0; i < nInsert; i++) { - SpGistLeafTuple lt = (SpGistLeafTuple) ptr; + char *leafTuple; + SpGistLeafTupleData leafTupleHdr; - addOrReplaceTuple(page, (Item) lt, lt->size, toInsert[i]); - ptr += lt->size; + /* + * the tuples are not aligned, so must copy to access + * the size field. + */ + leafTuple = ptr; + memcpy(&leafTupleHdr, leafTuple, + sizeof(SpGistLeafTupleData)); + + addOrReplaceTuple(page, (Item) leafTuple, + leafTupleHdr.size, toInsert[i]); + ptr += leafTupleHdr.size; } PageSetLSN(page, lsn); @@ -321,15 +333,17 @@ spgRedoAddNode(XLogRecPtr lsn, XLogRecord *record) { char *ptr = XLogRecGetData(record); spgxlogAddNode *xldata = (spgxlogAddNode *) ptr; - SpGistInnerTuple innerTuple; + char *innerTuple; + SpGistInnerTupleData innerTupleHdr; SpGistState state; Buffer buffer; Page page; int bbi; - /* we assume this is adequately aligned */ ptr += sizeof(spgxlogAddNode); - innerTuple = (SpGistInnerTuple) ptr; + innerTuple = ptr; + /* the tuple is unaligned, so make a copy to access its header */ + memcpy(&innerTupleHdr, innerTuple, sizeof(SpGistInnerTupleData)); fillFakeState(&state, xldata->stateSrc); @@ -348,11 +362,11 @@ spgRedoAddNode(XLogRecPtr lsn, XLogRecord *record) if (lsn > PageGetLSN(page)) { PageIndexTupleDelete(page, xldata->offnum); - if (PageAddItem(page, (Item) innerTuple, innerTuple->size, + if (PageAddItem(page, (Item) innerTuple, innerTupleHdr.size, xldata->offnum, false, false) != xldata->offnum) elog(ERROR, "failed to add item of size %u to SPGiST index page", - innerTuple->size); + innerTupleHdr.size); PageSetLSN(page, lsn); MarkBufferDirty(buffer); @@ -393,7 +407,7 @@ spgRedoAddNode(XLogRecPtr lsn, XLogRecord *record) if (lsn > PageGetLSN(page)) { addOrReplaceTuple(page, (Item) innerTuple, - innerTuple->size, xldata->offnumNew); + innerTupleHdr.size, xldata->offnumNew); /* * If parent is in this same page, don't advance LSN; @@ -508,16 +522,21 @@ spgRedoSplitTuple(XLogRecPtr lsn, XLogRecord *record) { char *ptr = XLogRecGetData(record); spgxlogSplitTuple *xldata = (spgxlogSplitTuple *) ptr; - SpGistInnerTuple prefixTuple; - SpGistInnerTuple postfixTuple; + char *prefixTuple; + SpGistInnerTupleData prefixTupleHdr; + char *postfixTuple; + SpGistInnerTupleData postfixTupleHdr; Buffer buffer; Page page; - /* we assume this is adequately aligned */ ptr += sizeof(spgxlogSplitTuple); - prefixTuple = (SpGistInnerTuple) ptr; - ptr += prefixTuple->size; - postfixTuple = (SpGistInnerTuple) ptr; + prefixTuple = ptr; + /* the prefix tuple is unaligned, so make a copy to access its header */ + memcpy(&prefixTupleHdr, prefixTuple, sizeof(SpGistInnerTupleData)); + ptr += prefixTupleHdr.size; + postfixTuple = ptr; + /* postfix tuple is also unaligned */ + memcpy(&postfixTupleHdr, postfixTuple, sizeof(SpGistInnerTupleData)); /* * In normal operation we would have both pages locked simultaneously; but @@ -543,7 +562,7 @@ spgRedoSplitTuple(XLogRecPtr lsn, XLogRecord *record) if (lsn > PageGetLSN(page)) { addOrReplaceTuple(page, (Item) postfixTuple, - postfixTuple->size, xldata->offnumPostfix); + postfixTupleHdr.size, xldata->offnumPostfix); PageSetLSN(page, lsn); MarkBufferDirty(buffer); @@ -564,14 +583,14 @@ spgRedoSplitTuple(XLogRecPtr lsn, XLogRecord *record) if (lsn > PageGetLSN(page)) { PageIndexTupleDelete(page, xldata->offnumPrefix); - if (PageAddItem(page, (Item) prefixTuple, prefixTuple->size, + if (PageAddItem(page, (Item) prefixTuple, prefixTupleHdr.size, xldata->offnumPrefix, false, false) != xldata->offnumPrefix) elog(ERROR, "failed to add item of size %u to SPGiST index page", - prefixTuple->size); + prefixTupleHdr.size); if (xldata->blknoPostfix == xldata->blknoPrefix) addOrReplaceTuple(page, (Item) postfixTuple, - postfixTuple->size, + postfixTupleHdr.size, xldata->offnumPostfix); PageSetLSN(page, lsn); @@ -587,7 +606,8 @@ spgRedoPickSplit(XLogRecPtr lsn, XLogRecord *record) { char *ptr = XLogRecGetData(record); spgxlogPickSplit *xldata = (spgxlogPickSplit *) ptr; - SpGistInnerTuple innerTuple; + char *innerTuple; + SpGistInnerTupleData innerTupleHdr; SpGistState state; OffsetNumber *toDelete; OffsetNumber *toInsert; @@ -602,15 +622,18 @@ spgRedoPickSplit(XLogRecPtr lsn, XLogRecord *record) fillFakeState(&state, xldata->stateSrc); - ptr += MAXALIGN(sizeof(spgxlogPickSplit)); - innerTuple = (SpGistInnerTuple) ptr; - ptr += innerTuple->size; + ptr += SizeOfSpgxlogPickSplit; toDelete = (OffsetNumber *) ptr; - ptr += MAXALIGN(sizeof(OffsetNumber) * xldata->nDelete); + ptr += sizeof(OffsetNumber) * xldata->nDelete; toInsert = (OffsetNumber *) ptr; - ptr += MAXALIGN(sizeof(OffsetNumber) * xldata->nInsert); + ptr += sizeof(OffsetNumber) * xldata->nInsert; leafPageSelect = (uint8 *) ptr; - ptr += MAXALIGN(sizeof(uint8) * xldata->nInsert); + ptr += sizeof(uint8) * xldata->nInsert; + + innerTuple = ptr; + /* the inner tuple is unaligned, so make a copy to access its header */ + memcpy(&innerTupleHdr, innerTuple, sizeof(SpGistInnerTupleData)); + ptr += innerTupleHdr.size; /* now ptr points to the list of leaf tuples */ @@ -735,15 +758,20 @@ spgRedoPickSplit(XLogRecPtr lsn, XLogRecord *record) /* restore leaf tuples to src and/or dest page */ for (i = 0; i < xldata->nInsert; i++) { - SpGistLeafTuple lt = (SpGistLeafTuple) ptr; + char *leafTuple; + SpGistLeafTupleData leafTupleHdr; - ptr += lt->size; + /* the tuples are not aligned, so must copy to access the size field. */ + leafTuple = ptr; + memcpy(&leafTupleHdr, leafTuple, sizeof(SpGistLeafTupleData)); + ptr += leafTupleHdr.size; page = leafPageSelect[i] ? destPage : srcPage; if (page == NULL) continue; /* no need to touch this page */ - addOrReplaceTuple(page, (Item) lt, lt->size, toInsert[i]); + addOrReplaceTuple(page, (Item) leafTuple, leafTupleHdr.size, + toInsert[i]); } /* Now update src and dest page LSNs if needed */ @@ -776,7 +804,7 @@ spgRedoPickSplit(XLogRecPtr lsn, XLogRecord *record) if (lsn > PageGetLSN(page)) { - addOrReplaceTuple(page, (Item) innerTuple, innerTuple->size, + addOrReplaceTuple(page, (Item) innerTuple, innerTupleHdr.size, xldata->offnumInner); /* if inner is also parent, update link while we're here */ @@ -861,7 +889,7 @@ spgRedoVacuumLeaf(XLogRecPtr lsn, XLogRecord *record) fillFakeState(&state, xldata->stateSrc); - ptr += sizeof(spgxlogVacuumLeaf); + ptr += SizeOfSpgxlogVacuumLeaf; toDead = (OffsetNumber *) ptr; ptr += sizeof(OffsetNumber) * xldata->nDead; toPlaceholder = (OffsetNumber *) ptr; @@ -941,8 +969,7 @@ spgRedoVacuumRoot(XLogRecPtr lsn, XLogRecord *record) Buffer buffer; Page page; - ptr += sizeof(spgxlogVacuumRoot); - toDelete = (OffsetNumber *) ptr; + toDelete = xldata->offsets; if (record->xl_info & XLR_BKP_BLOCK(0)) (void) RestoreBackupBlock(lsn, record, 0, false, false); @@ -974,8 +1001,7 @@ spgRedoVacuumRedirect(XLogRecPtr lsn, XLogRecord *record) Buffer buffer; Page page; - ptr += sizeof(spgxlogVacuumRedirect); - itemToPlaceholder = (OffsetNumber *) ptr; + itemToPlaceholder = xldata->offsets; /* * If any redirection tuples are being removed, make sure there are no |