mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Install defenses against overflow in BuildTupleHashTable().
The planner can sometimes compute very large values for numGroups, and in cases where we have no alternative to building a hashtable, such a value will get fed directly to BuildTupleHashTable as its nbuckets parameter. There were two ways in which that could go bad. First, BuildTupleHashTable declared the parameter as "int" but most callers were passing "long"s, so on 64-bit machines undetected overflow could occur leading to a bogus negative value. The obvious fix for that is to change the parameter to "long", which is what I've done in HEAD. In the back branches that seems a bit risky, though, since third-party code might be calling this function. So for them, just put in a kluge to treat negative inputs as INT_MAX. Second, hash_create can go nuts with extremely large requested table sizes (notably, my_log2 becomes an infinite loop for inputs larger than LONG_MAX/2). What seems most appropriate to avoid that is to bound the initial table size request to work_mem. This fixes bug #6035 reported by Daniel Schreiber. Although the reported case only occurs back to 8.4 since it involves WITH RECURSIVE, I think it's a good idea to install the defenses in all supported branches.
This commit is contained in:
parent
a9b6519606
commit
299d171652
@ -19,6 +19,7 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
#include "parser/parse_oper.h"
|
#include "parser/parse_oper.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
@ -276,7 +277,7 @@ TupleHashTable
|
|||||||
BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
|
BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
|
||||||
FmgrInfo *eqfunctions,
|
FmgrInfo *eqfunctions,
|
||||||
FmgrInfo *hashfunctions,
|
FmgrInfo *hashfunctions,
|
||||||
int nbuckets, Size entrysize,
|
long nbuckets, Size entrysize,
|
||||||
MemoryContext tablecxt, MemoryContext tempcxt)
|
MemoryContext tablecxt, MemoryContext tempcxt)
|
||||||
{
|
{
|
||||||
TupleHashTable hashtable;
|
TupleHashTable hashtable;
|
||||||
@ -285,6 +286,9 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
|
|||||||
Assert(nbuckets > 0);
|
Assert(nbuckets > 0);
|
||||||
Assert(entrysize >= sizeof(TupleHashEntryData));
|
Assert(entrysize >= sizeof(TupleHashEntryData));
|
||||||
|
|
||||||
|
/* Limit initial table size request to not more than work_mem */
|
||||||
|
nbuckets = Min(nbuckets, (long) ((work_mem * 1024L) / entrysize));
|
||||||
|
|
||||||
hashtable = (TupleHashTable) MemoryContextAlloc(tablecxt,
|
hashtable = (TupleHashTable) MemoryContextAlloc(tablecxt,
|
||||||
sizeof(TupleHashTableData));
|
sizeof(TupleHashTableData));
|
||||||
|
|
||||||
@ -306,7 +310,7 @@ BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
|
|||||||
hash_ctl.hash = TupleHashTableHash;
|
hash_ctl.hash = TupleHashTableHash;
|
||||||
hash_ctl.match = TupleHashTableMatch;
|
hash_ctl.match = TupleHashTableMatch;
|
||||||
hash_ctl.hcxt = tablecxt;
|
hash_ctl.hcxt = tablecxt;
|
||||||
hashtable->hashtab = hash_create("TupleHashTable", (long) nbuckets,
|
hashtable->hashtab = hash_create("TupleHashTable", nbuckets,
|
||||||
&hash_ctl,
|
&hash_ctl,
|
||||||
HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT);
|
HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT);
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
|
|||||||
int ncols = list_length(subplan->paramIds);
|
int ncols = list_length(subplan->paramIds);
|
||||||
ExprContext *innerecontext = node->innerecontext;
|
ExprContext *innerecontext = node->innerecontext;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
int nbuckets;
|
long nbuckets;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
|
||||||
Assert(subplan->subLinkType == ANY_SUBLINK);
|
Assert(subplan->subLinkType == ANY_SUBLINK);
|
||||||
@ -458,7 +458,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
|
|||||||
node->havehashrows = false;
|
node->havehashrows = false;
|
||||||
node->havenullrows = false;
|
node->havenullrows = false;
|
||||||
|
|
||||||
nbuckets = (int) ceil(planstate->plan->plan_rows);
|
nbuckets = (long) Min(planstate->plan->plan_rows, (double) LONG_MAX);
|
||||||
if (nbuckets < 1)
|
if (nbuckets < 1)
|
||||||
nbuckets = 1;
|
nbuckets = 1;
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ extern void execTuplesHashPrepare(int numCols,
|
|||||||
extern TupleHashTable BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
|
extern TupleHashTable BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
|
||||||
FmgrInfo *eqfunctions,
|
FmgrInfo *eqfunctions,
|
||||||
FmgrInfo *hashfunctions,
|
FmgrInfo *hashfunctions,
|
||||||
int nbuckets, Size entrysize,
|
long nbuckets, Size entrysize,
|
||||||
MemoryContext tablecxt,
|
MemoryContext tablecxt,
|
||||||
MemoryContext tempcxt);
|
MemoryContext tempcxt);
|
||||||
extern TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable,
|
extern TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user