From c02b56869439281d139d47dae784e3f7cf765f2d Mon Sep 17 00:00:00 2001 From: Andrew Gierth Date: Tue, 11 Sep 2018 18:14:19 +0100 Subject: Repair double-free in SP-GIST rescan (bug #15378) spgrescan would first reset traversalCxt, and then traverse a potentially non-empty stack containing pointers to traversalValues which had been allocated in those contexts, freeing them a second time. This bug originates in commit ccd6eb49a where traversalValue was introduced. Repair by traversing the stack before the context reset; this isn't ideal, since it means doing retail pfree in a context that's about to be reset, but the freeing of a stack entry is also done in other places in the code during the scan so it's not worth trying to refactor it further. Regression test added. Backpatch to 9.6 where the problem was introduced. Per bug #15378; analysis and patch by me, originally from a report on IRC by user velix; see also PostGIS ticket #4174; review by Alexander Korotkov. Discussion: https://postgr.es/m/153663176628.23136.11901365223750051490@wrigleys.postgresql.org --- src/backend/access/spgist/spgscan.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/backend/access/spgist/spgscan.c') diff --git a/src/backend/access/spgist/spgscan.c b/src/backend/access/spgist/spgscan.c index adcee037e66..ae0e0a9e730 100644 --- a/src/backend/access/spgist/spgscan.c +++ b/src/backend/access/spgist/spgscan.c @@ -74,6 +74,13 @@ resetSpGistScanOpaque(SpGistScanOpaque so) freeScanStack(so); + /* + * clear traversal context before proceeding to the next scan; this must + * not happen before the freeScanStack above, else we get double-free + * crashes. + */ + MemoryContextReset(so->traversalCxt); + if (so->searchNulls) { /* Stack a work item to scan the null index entries */ @@ -212,9 +219,6 @@ spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, { SpGistScanOpaque so = (SpGistScanOpaque) scan->opaque; - /* clear traversal context before proceeding to the next scan */ - MemoryContextReset(so->traversalCxt); - /* copy scankeys into local storage */ if (scankey && scan->numberOfKeys > 0) { -- cgit v1.2.3