postgres.git / summary / log / commit / refs

commit    8f72bbac3e4b1d1be9598e8edb9353fa5dc48138
Author:   Peter Geoghegan <pg@bowt.ie>
Date:     Fri May 14 22:08:02 2021 +0000

    Harden nbtree deduplication posting split code.
    
    Add a defensive "can't happen" error to code that handles nbtree posting
    list splits (promote an existing assertion).  This avoids a segfault in
    the event of an insertion of a newitem that is somehow identical to an
    existing non-pivot tuple in the index.  An nbtree index should never
    have two index tuples with identical TIDs.
    
    This scenario is not particular unlikely in the event of any kind of
    corruption that leaves the index in an inconsistent state relative to
    the heap relation that is indexed.  There are two known reports of
    preventable hard crashes.  Doing nothing seems unacceptable given the
    general expectation that nbtree will cope reasonably well with corrupt
    data.
    
    Discussion: https://postgr.es/m/CAH2-Wz=Jr_d-dOYEEmwz0-ifojVNWho01eAqewfQXgKfoe114w@mail.gmail.com
    Backpatch: 13-, where nbtree deduplication was introduced.


src/backend/access/nbtree/nbtdedup.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c index 854e3b2cf9a..271994b08df 100644 --- a/src/backend/access/nbtree/nbtdedup.c +++ b/src/backend/access/nbtree/nbtdedup.c @@ -1024,7 +1024,19 @@ _bt_swap_posting(IndexTuple newitem, IndexTuple oposting, int postingoff) nhtids = BTreeTupleGetNPosting(oposting); Assert(_bt_posting_valid(oposting)); - Assert(postingoff > 0 && postingoff < nhtids); + + /* + * The postingoff argument originated as a _bt_binsrch_posting() return + * value. It will be 0 in the event of corruption that makes a leaf page + * contain a non-pivot tuple that's somehow identical to newitem (no two + * non-pivot tuples should ever have the same TID). This has been known + * to happen in the field from time to time. + * + * Perform a basic sanity check to catch this case now. + */ + if (!(postingoff > 0 && postingoff < nhtids)) + elog(ERROR, "posting list tuple with %d items cannot be split at offset %d", + nhtids, postingoff); /* * Move item pointers in posting list to make a gap for the new item's [parent: c3c35a733c77]