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);
205207static int choose_nelem_alloc (Size entrysize );
206208static bool init_htab (HTAB * hashp , long nelem );
207209static void hash_corrupted (HTAB * hashp );
210+ static long next_pow2_long (long num );
211+ static int next_pow2_int (long num );
208212static void register_seq_scan (HTAB * hashp );
209213static void deregister_seq_scan (HTAB * hashp );
210214static bool has_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- long lnbuckets ;
527535 int nbuckets ;
528536 int nsegs ;
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 int i ;
14091415 long limit ;
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 return i ;
14141424}
14151425
1426+ /* calculate first power of 2 >= num, bounded to what will fit in a long */
1427+ static long
1428+ next_pow2_long (long num )
1429+ {
1430+ /* my_log2's internal range check is sufficient */
1431+ return 1L << my_log2 (num );
1432+ }
1433+
1434+ /* calculate first power of 2 >= num, bounded to what will fit in an int */
1435+ static int
1436+ next_pow2_int (long num )
1437+ {
1438+ if (num > INT_MAX / 2 )
1439+ num = INT_MAX / 2 ;
1440+ return 1 << my_log2 (num );
1441+ }
1442+
14161443
14171444/************************* SEQ SCAN TRACKING ************************/
14181445
0 commit comments