diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c index 48514a3b781..50201780204 100644 --- a/src/backend/nodes/bitmapset.c +++ b/src/backend/nodes/bitmapset.c @@ -1010,6 +1010,7 @@ bms_offset_members(Bitmapset *a, int offset) int new_nwords; int old_nwords; int32 high_bit; + int64 old_highest; Assert(bms_is_valid_set(a)); @@ -1022,6 +1023,7 @@ bms_offset_members(Bitmapset *a, int offset) offset_bits = BITNUM(offset); new_nwords = a->nwords + offset_words; high_bit = bmw_leftmost_one_pos(a->words[a->nwords - 1]); + old_highest = ((int64) a->nwords - 1) * BITS_PER_BITMAPWORD + high_bit; /* Adjust the number of words in the new set to how many we'll need */ new_nwords += (offset_bits + high_bit) >= BITS_PER_BITMAPWORD; @@ -1041,7 +1043,8 @@ bms_offset_members(Bitmapset *a, int offset) * An unlikely scenario, but check we're not going to create a member * greater than PG_INT32_MAX. */ - if (((uint64) new_nwords - 1) * BITS_PER_BITMAPWORD + high_bit + offset_bits > PG_INT32_MAX) + /*if (((uint64) new_nwords - 1) * BITS_PER_BITMAPWORD + high_bit + offset_bits > PG_INT32_MAX)*/ + if (old_highest + offset > PG_INT32_MAX) elog(ERROR, "bitmapset overflow"); /* diff --git a/src/test/modules/test_bitmapset/expected/test_bitmapset.out b/src/test/modules/test_bitmapset/expected/test_bitmapset.out index 3a6f08427cd..984174cfaf7 100644 --- a/src/test/modules/test_bitmapset/expected/test_bitmapset.out +++ b/src/test/modules/test_bitmapset/expected/test_bitmapset.out @@ -1613,4 +1613,14 @@ SELECT test_random_offset_operations(-1, 10000, 1024, 0) AS result; 10000 (1 row) +-- 2147483583 is PG_INT32_MAX - 64, so offsetting by 1 should succeed, +-- but offsetting it by 65 should fail with overflow error +SELECT test_random_offset_operations_check_highest(2147483583, 1) AS result; + result +------------ + 2147483584 +(1 row) + +SELECT test_random_offset_operations_check_highest(2147483583, 65) AS result; +ERROR: bitmapset overflow DROP EXTENSION test_bitmapset; diff --git a/src/test/modules/test_bitmapset/sql/test_bitmapset.sql b/src/test/modules/test_bitmapset/sql/test_bitmapset.sql index 5c5cfe3fc15..072d264ad9a 100644 --- a/src/test/modules/test_bitmapset/sql/test_bitmapset.sql +++ b/src/test/modules/test_bitmapset/sql/test_bitmapset.sql @@ -416,4 +416,9 @@ SELECT test_random_operations(-1, 10000, 81920, 0) > 0 AS result; -- perform some random test on bms_offset_members() SELECT test_random_offset_operations(-1, 10000, 1024, 0) AS result; +-- 2147483583 is PG_INT32_MAX - 64, so offsetting by 1 should succeed, +-- but offsetting it by 65 should fail with overflow error +SELECT test_random_offset_operations_check_highest(2147483583, 1) AS result; +SELECT test_random_offset_operations_check_highest(2147483583, 65) AS result; + DROP EXTENSION test_bitmapset; diff --git a/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql b/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql index ea12ec40057..88bf6719aa6 100644 --- a/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql +++ b/src/test/modules/test_bitmapset/test_bitmapset--1.0.sql @@ -145,4 +145,8 @@ CREATE FUNCTION test_random_offset_operations(integer, integer, integer, integer RETURNS integer STRICT AS 'MODULE_PATHNAME' LANGUAGE C; +CREATE FUNCTION test_random_offset_operations_check_highest(integer, integer) +RETURNS integer STRICT +AS 'MODULE_PATHNAME' LANGUAGE C; + COMMENT ON EXTENSION test_bitmapset IS 'Test code for Bitmapset'; diff --git a/src/test/modules/test_bitmapset/test_bitmapset.c b/src/test/modules/test_bitmapset/test_bitmapset.c index 1fbf9ffc200..59da3fb78ca 100644 --- a/src/test/modules/test_bitmapset/test_bitmapset.c +++ b/src/test/modules/test_bitmapset/test_bitmapset.c @@ -67,6 +67,7 @@ PG_FUNCTION_INFO_V1(test_bitmap_match); /* Test utility functions */ PG_FUNCTION_INFO_V1(test_random_operations); PG_FUNCTION_INFO_V1(test_random_offset_operations); +PG_FUNCTION_INFO_V1(test_random_offset_operations_check_highest); /* Convenient macros to test results */ #define EXPECT_TRUE(expr) \ @@ -827,3 +828,20 @@ test_random_offset_operations(PG_FUNCTION_ARGS) PG_RETURN_INT32(num_ops); } + +Datum +test_random_offset_operations_check_highest(PG_FUNCTION_ARGS) +{ + int highest_member = 0; + int offset = 0; + Bitmapset *bms; + + highest_member = PG_GETARG_INT32(0); + offset = PG_GETARG_INT32(1); + + bms = bms_add_member(NULL, highest_member); + bms = bms_offset_members(bms, offset); + highest_member = bms_next_member(bms, -1); + + PG_RETURN_INT32(highest_member); +} \ No newline at end of file