Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit691c5eb

Browse files
committed
Add defenses against integer overflow in dynahash numbuckets calculations.
The dynahash code requires the number of buckets in a hash table to fitin an int; but since we calculate the desired hash table size dynamically,there are various scenarios where we might calculate too large a value.The resulting overflow can lead to infinite loops, division-by-zerocrashes, etc. I (tgl) had previously installed some defenses against thatin commit299d171, but that covered only onecall path. Moreover it worked by limiting the request size to work_mem,but in a 64-bit machine it's possible to set work_mem high enough that theproblem appears anyway. So let's fix the problem at the root by installinglimits in the dynahash.c functions themselves.Trouble report and patch by Jeff Davis.
1 parentcd3413e commit691c5eb

File tree

2 files changed

+41
-12
lines changed

2 files changed

+41
-12
lines changed

‎src/backend/executor/nodeHash.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,9 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew,
500500
* Both nbuckets and nbatch must be powers of 2 to make
501501
* ExecHashGetBucketAndBatch fast.We already fixed nbatch; now inflate
502502
* nbuckets to the next larger power of 2.We also force nbuckets to not
503-
* be real small, by starting the search at 2^10.
503+
* be real small, by starting the search at 2^10. (Note: above we made
504+
* sure that nbuckets is not more than INT_MAX / 2, so this loop cannot
505+
* overflow, nor can the final shift to recalculate nbuckets.)
504506
*/
505507
i=10;
506508
while ((1 <<i)<nbuckets)

‎src/backend/utils/hash/dynahash.c

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868

6969
#include"postgres.h"
7070

71+
#include<limits.h>
72+
7173
#include"access/xact.h"
7274
#include"storage/shmem.h"
7375
#include"storage/spin.h"
@@ -205,6 +207,8 @@ static void hdefault(HTAB *hashp);
205207
staticintchoose_nelem_alloc(Sizeentrysize);
206208
staticboolinit_htab(HTAB*hashp,longnelem);
207209
staticvoidhash_corrupted(HTAB*hashp);
210+
staticlongnext_pow2_long(longnum);
211+
staticintnext_pow2_int(longnum);
208212
staticvoidregister_seq_scan(HTAB*hashp);
209213
staticvoidderegister_seq_scan(HTAB*hashp);
210214
staticboolhas_seq_scans(HTAB*hashp);
@@ -379,8 +383,13 @@ hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
379383
{
380384
/* Doesn't make sense to partition a local hash table */
381385
Assert(flags&HASH_SHARED_MEM);
382-
/* # of partitions had better be a power of 2 */
383-
Assert(info->num_partitions== (1L <<my_log2(info->num_partitions)));
386+
387+
/*
388+
* The number of partitions had better be a power of 2. Also, it must
389+
* be less than INT_MAX (see init_htab()), so call the int version of
390+
* next_pow2.
391+
*/
392+
Assert(info->num_partitions==next_pow2_int(info->num_partitions));
384393

385394
hctl->num_partitions=info->num_partitions;
386395
}
@@ -523,7 +532,6 @@ init_htab(HTAB *hashp, long nelem)
523532
{
524533
HASHHDR*hctl=hashp->hctl;
525534
HASHSEGMENT*segp;
526-
longlnbuckets;
527535
intnbuckets;
528536
intnsegs;
529537

@@ -538,9 +546,7 @@ init_htab(HTAB *hashp, long nelem)
538546
* number of buckets. Allocate space for the next greater power of two
539547
* number of buckets
540548
*/
541-
lnbuckets= (nelem-1) /hctl->ffactor+1;
542-
543-
nbuckets=1 <<my_log2(lnbuckets);
549+
nbuckets=next_pow2_int((nelem-1) /hctl->ffactor+1);
544550

545551
/*
546552
* In a partitioned table, nbuckets must be at least equal to
@@ -558,7 +564,7 @@ init_htab(HTAB *hashp, long nelem)
558564
* Figure number of directory segments needed, round up to a power of 2
559565
*/
560566
nsegs= (nbuckets-1) /hctl->ssize+1;
561-
nsegs=1 <<my_log2(nsegs);
567+
nsegs=next_pow2_int(nsegs);
562568

563569
/*
564570
* Make sure directory is big enough. If pre-allocated directory is too
@@ -628,9 +634,9 @@ hash_estimate_size(long num_entries, Size entrysize)
628634
elementAllocCnt;
629635

630636
/* estimate number of buckets wanted */
631-
nBuckets=1L <<my_log2((num_entries-1) /DEF_FFACTOR+1);
637+
nBuckets=next_pow2_long((num_entries-1) /DEF_FFACTOR+1);
632638
/* # of segments needed for nBuckets */
633-
nSegments=1L <<my_log2((nBuckets-1) /DEF_SEGSIZE+1);
639+
nSegments=next_pow2_long((nBuckets-1) /DEF_SEGSIZE+1);
634640
/* directory entries */
635641
nDirEntries=DEF_DIRSIZE;
636642
while (nDirEntries<nSegments)
@@ -671,9 +677,9 @@ hash_select_dirsize(long num_entries)
671677
nDirEntries;
672678

673679
/* estimate number of buckets wanted */
674-
nBuckets=1L <<my_log2((num_entries-1) /DEF_FFACTOR+1);
680+
nBuckets=next_pow2_long((num_entries-1) /DEF_FFACTOR+1);
675681
/* # of segments needed for nBuckets */
676-
nSegments=1L <<my_log2((nBuckets-1) /DEF_SEGSIZE+1);
682+
nSegments=next_pow2_long((nBuckets-1) /DEF_SEGSIZE+1);
677683
/* directory entries */
678684
nDirEntries=DEF_DIRSIZE;
679685
while (nDirEntries<nSegments)
@@ -1408,11 +1414,32 @@ my_log2(long num)
14081414
inti;
14091415
longlimit;
14101416

1417+
/* guard against too-large input, which would put us into infinite loop */
1418+
if (num>LONG_MAX /2)
1419+
num=LONG_MAX /2;
1420+
14111421
for (i=0,limit=1;limit<num;i++,limit <<=1)
14121422
;
14131423
returni;
14141424
}
14151425

1426+
/* calculate first power of 2 >= num, bounded to what will fit in a long */
1427+
staticlong
1428+
next_pow2_long(longnum)
1429+
{
1430+
/* my_log2's internal range check is sufficient */
1431+
return1L <<my_log2(num);
1432+
}
1433+
1434+
/* calculate first power of 2 >= num, bounded to what will fit in an int */
1435+
staticint
1436+
next_pow2_int(longnum)
1437+
{
1438+
if (num>INT_MAX /2)
1439+
num=INT_MAX /2;
1440+
return1 <<my_log2(num);
1441+
}
1442+
14161443

14171444
/************************* SEQ SCAN TRACKING ************************/
14181445

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp