summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Geoghegan <pg@bowt.ie>2021-05-14 15:08:00 -0700
committerPeter Geoghegan <pg@bowt.ie>2021-05-14 15:08:00 -0700
commitfa675af59fc828d0b71bd9139042d71456640a28 (patch)
tree6d3e5e6b8a9313fea16cb8487b7fe6586051542a
parent6a4c07156802fa2efee75c273a7d5d9ae81bda28 (diff)
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.
-rw-r--r--src/backend/access/nbtree/nbtdedup.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c
index f6be865b17e..cb53ce45782 100644
--- a/src/backend/access/nbtree/nbtdedup.c
+++ b/src/backend/access/nbtree/nbtdedup.c
@@ -781,7 +781,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