Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 96ba40c

Browse files
committed
Guard against possible memory allocation botch in batchmemtuples().
Negative availMemLessRefund would be problematic. It's not entirely clear whether the case can be hit in the code as it stands, but this seems like good future-proofing in any case. While we're at it, insist that the value be not merely positive but not tiny, so as to avoid doing a lot of repalloc work for little gain. Peter Geoghegan Discussion: <CAM3SWZRVkuUB68DbAkgw=532gW0f+fofKueAMsY7hVYi68MuYQ@mail.gmail.com>
1 parent 512c197 commit 96ba40c

File tree

1 file changed

+21
-2
lines changed

1 file changed

+21
-2
lines changed

src/backend/utils/sort/tuplesort.c

+21-2
Original file line numberDiff line numberDiff line change
@@ -2866,6 +2866,9 @@ batchmemtuples(Tuplesortstate *state)
28662866
int64 availMemLessRefund;
28672867
int memtupsize = state->memtupsize;
28682868

2869+
/* Caller error if we have no tapes */
2870+
Assert(state->activeTapes > 0);
2871+
28692872
/* For simplicity, assume no memtuples are actually currently counted */
28702873
Assert(state->memtupcount == 0);
28712874

@@ -2879,6 +2882,20 @@ batchmemtuples(Tuplesortstate *state)
28792882
refund = memtupsize * STANDARDCHUNKHEADERSIZE;
28802883
availMemLessRefund = state->availMem - refund;
28812884

2885+
/*
2886+
* We need to be sure that we do not cause LACKMEM to become true, else
2887+
* the batch allocation size could be calculated as negative, causing
2888+
* havoc. Hence, if availMemLessRefund is negative at this point, we must
2889+
* do nothing. Moreover, if it's positive but rather small, there's
2890+
* little point in proceeding because we could only increase memtuples by
2891+
* a small amount, not worth the cost of the repalloc's. We somewhat
2892+
* arbitrarily set the threshold at ALLOCSET_DEFAULT_INITSIZE per tape.
2893+
* (Note that this does not represent any assumption about tuple sizes.)
2894+
*/
2895+
if (availMemLessRefund <=
2896+
(int64) state->activeTapes * ALLOCSET_DEFAULT_INITSIZE)
2897+
return;
2898+
28822899
/*
28832900
* To establish balanced memory use after refunding palloc overhead,
28842901
* temporarily have our accounting indicate that we've allocated all
@@ -2888,9 +2905,11 @@ batchmemtuples(Tuplesortstate *state)
28882905
state->growmemtuples = true;
28892906
USEMEM(state, availMemLessRefund);
28902907
(void) grow_memtuples(state);
2891-
/* Should not matter, but be tidy */
2892-
FREEMEM(state, availMemLessRefund);
28932908
state->growmemtuples = false;
2909+
/* availMem must stay accurate for spacePerTape calculation */
2910+
FREEMEM(state, availMemLessRefund);
2911+
if (LACKMEM(state))
2912+
elog(ERROR, "unexpected out-of-memory situation in tuplesort");
28942913

28952914
#ifdef TRACE_SORT
28962915
if (trace_sort)

0 commit comments

Comments
 (0)