From ecfe770d4ef8139d6f852dde5037a7eb51715e89 Mon Sep 17 00:00:00 2001
From: Greg Burd <greg@burd.me>
Date: Wed, 8 Oct 2025 14:27:30 -0400
Subject: [PATCH v1] Correct flaws in randomized Bitmapset tests

There were two oversights in the function designated to perform
randomized tests against Bitmapset.  First, the test validating
bms_union() was not checking the return from bms_is_member() and so
wasn't testing much at all.  Second, in the second half of this function
performing randomized operations there was no tracking of what members
should exist after some number of random add/del operations.  This patch
addresses both of those issues.

Reported-by: Ranier Vilela<ranier.vf@gmail.com>
Discussion: https://postgr.es/m/CAApHDvqghMnm_zgSNefto9oaEJ0S-3Cgb3gdsV7XvLC-hMS02Q@mail.gmail.com
---
 .../modules/test_bitmapset/test_bitmapset.c   | 31 ++++++++++++++-----
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/src/test/modules/test_bitmapset/test_bitmapset.c b/src/test/modules/test_bitmapset/test_bitmapset.c
index 8bc9b1f48e9..00651cb8df1 100644
--- a/src/test/modules/test_bitmapset/test_bitmapset.c
+++ b/src/test/modules/test_bitmapset/test_bitmapset.c
@@ -624,10 +624,8 @@ test_random_operations(PG_FUNCTION_ARGS)
 		member = pg_prng_uint32(&state) % max_range + min_value;
 
 		if (!bms_is_member(member, bms1))
-		{
 			members[num_members++] = member;
-			bms1 = bms_add_member(bms1, member);
-		}
+		bms1 = bms_add_member(bms1, member);
 	}
 
 	/* Phase 2: Random set operations */
@@ -635,6 +633,8 @@ test_random_operations(PG_FUNCTION_ARGS)
 	{
 		member = pg_prng_uint32(&state) % max_range + min_value;
 
+		if (!bms_is_member(member, bms1) && !bms_is_member(member, bms2))
+			members[num_members++] = member;
 		bms2 = bms_add_member(bms2, member);
 	}
 
@@ -683,24 +683,39 @@ test_random_operations(PG_FUNCTION_ARGS)
 	bms_free(bms1);
 	bms_free(bms2);
 
-	for (int i = 0; i < num_ops; i++)
+	num_members = 0;
+	members = palloc(sizeof(int) * num_ops);
+
+	for (int op = 0; op < num_ops; op++)
 	{
-		member = pg_prng_uint32(&state) % max_range + min_value;
 		switch (pg_prng_uint32(&state) % 3)
 		{
 			case 0:				/* add */
+				member = pg_prng_uint32(&state) % max_range + min_value;
+				if (!bms_is_member(member, bms))
+					members[num_members++] = member;
 				bms = bms_add_member(bms, member);
 				break;
 			case 1:				/* delete */
-				if (bms != NULL)
+				if (num_members > 0)
 				{
+					int			pos = pg_prng_uint32(&state) % num_members;
+
+					member = members[pos];
+					if (!bms_is_member(member, bms))
+						elog(ERROR, "expected %d to be a valid member", member);
 					bms = bms_del_member(bms, member);
+					num_members--;
+					memmove(members + pos, members + pos + 1,
+							(num_members - pos) * sizeof(int));
 				}
 				break;
 			case 2:				/* test membership */
-				if (bms != NULL)
+				/* Verify bitmap contains all members */
+				for (int i = 0; i < num_members; i++)
 				{
-					bms_is_member(member, bms);
+					if (!bms_is_member(members[i], bms))
+						elog(ERROR, "missing member %d", members[i]);
 				}
 				break;
 		}
-- 
2.49.0

