Postgresql 19 added a new module, src/test/modules/test_bitmapset.
It contains the function test_bms_membership(), which is a wrapper
around bms_membership. Passing some string that are not valid Bitmapset
representation to this function will result to assert. For example

SELECT test_bms_membership('b 1 2)');
or
SELECT test_bms_membership('true');

[backtrace.txt]

|The assertion appears to occur becaus| in
#define TEXT_TO_BITMAPSET(str) (test_bitmapset.c:91) casts to Bitmapset*
without type checking, using stringToNode, which obviously can return
types other than T_Bitmapset (read.c:247). This pointer, with the wrong
type, is then passed to bms_membership, where it fails the assert
with type checking (bitmapset.c:905).

The fix simply adds a check whether the type is valid or not,
as done in the bms_is_valid_set()(bitmapset.c:87) function.

---

Best regards,
Ilya Cherdakov
Postgres Professional: https://postgrespro.com
(gdb) bt
#0  __pthread_kill_implementation (threadid=<optimized out>, 
signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44
#1  0x00007fbfc389f9ff in __pthread_kill_internal (threadid=<optimized out>, 
signo=6) at ./nptl/pthread_kill.c:89
#2  0x00007fbfc384acc2 in __GI_raise (sig=sig@entry=6) at 
../sysdeps/posix/raise.c:26
#3  0x00007fbfc38334ac in __GI_abort () at ./stdlib/abort.c:77
#4  0x000055b02387ec15 in ExceptionalCondition 
(conditionName=conditionName@entry=0x55b0238f5bee "bms_is_valid_set(a)", 
fileName=fileName@entry=0x55b0238f5ec4 "bitmapset.c",
    lineNumber=lineNumber@entry=906) at assert.c:65
#5  0x000055b02357867d in bms_membership (a=<optimized out>) at bitmapset.c:906
#6  0x00007fbfc3db9e21 in test_bms_membership (fcinfo=<optimized out>) at 
test_bitmapset.c:254
#7  0x000055b0235138a1 in ExecInterpExpr (state=0x55b02cbf92c0, 
econtext=0x55b02cbf8f68, isnull=<optimized out>) at execExprInterp.c:936
#8  0x000055b023552475 in ExecEvalExprNoReturn (state=0x55b02cbf92c0, 
econtext=0x55b02cbf8f68) at ../../../src/include/executor/executor.h:431
#9  ExecEvalExprNoReturnSwitchContext (state=0x55b02cbf92c0, 
econtext=0x55b02cbf8f68) at ../../../src/include/executor/executor.h:472
#10 ExecProject (projInfo=0x55b02cbf92b8) at 
../../../src/include/executor/executor.h:504
#11 ExecResult (pstate=<optimized out>) at nodeResult.c:135
#12 0x000055b023517aeb in ExecProcNode (node=0x55b02cbf8e58) at 
../../../src/include/executor/executor.h:327
#13 ExecutePlan (queryDesc=0x55b02cb1f3c0, operation=CMD_SELECT, 
sendTuples=true, numberTuples=0, direction=<optimized out>, 
dest=0x55b02cbf77a0) at execMain.c:1776
#14 standard_ExecutorRun (queryDesc=0x55b02cb1f3c0, direction=<optimized out>, 
count=0) at execMain.c:377
#15 0x000055b0237236d8 in PortalRunSelect (portal=portal@entry=0x55b02cb7f600, 
forward=forward@entry=true, count=0, count@entry=9223372036854775807, 
dest=dest@entry=0x55b02cbf77a0) at pquery.c:917
#16 0x000055b023724cee in PortalRun (portal=portal@entry=0x55b02cb7f600, 
count=count@entry=9223372036854775807, isTopLevel=isTopLevel@entry=true, 
dest=dest@entry=0x55b02cbf77a0,
    altdest=altdest@entry=0x55b02cbf77a0, qc=qc@entry=0x7fffcda59a80) at 
pquery.c:761
#17 0x000055b02372082a in exec_simple_query (query_string=0x55b02caf6e40 
"SELECT test_bms_membership('true');") at postgres.c:1297
#18 0x000055b023722487 in PostgresMain (dbname=<optimized out>, 
username=<optimized out>) at postgres.c:4946
#19 0x000055b02371c54d in BackendMain (startup_data=<optimized out>, 
startup_data_len=<optimized out>) at backend_startup.c:124
#20 0x000055b02365f4c9 in postmaster_child_launch (child_type=<optimized out>, 
child_slot=1, startup_data=startup_data@entry=0x7fffcda59f20, 
startup_data_len=startup_data_len@entry=24,
    client_sock=client_sock@entry=0x7fffcda59f40) at launch_backend.c:268
#21 0x000055b023662f70 in BackendStartup (client_sock=0x7fffcda59f40) at 
postmaster.c:3643
#22 ServerLoop () at postmaster.c:1729
#23 0x000055b0236649ec in PostmasterMain (argc=argc@entry=3, 
argv=argv@entry=0x55b02caf1640) at postmaster.c:1416
#24 0x000055b023316d2a in main (argc=3, argv=0x55b02caf1640) at main.c:227
From d4caaef47d9821636c5629d2feaf02cfc60a96bc Mon Sep 17 00:00:00 2001
From: Ilya Cherdakov <[email protected]>
Date: Tue, 8 Sep 2026 14:13:16 +0300
Subject: [PATCH] Validate Bitmapset input in test_bitmapset

---
 .../modules/test_bitmapset/test_bitmapset.c     | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/test/modules/test_bitmapset/test_bitmapset.c 
b/src/test/modules/test_bitmapset/test_bitmapset.c
index af8c664949e..1fc6d618611 100644
--- a/src/test/modules/test_bitmapset/test_bitmapset.c
+++ b/src/test/modules/test_bitmapset/test_bitmapset.c
@@ -88,14 +88,27 @@ PG_FUNCTION_INFO_V1(test_random_offset_operations);
 
 /* Encode/Decode to/from TEXT and Bitmapset */
 #define BITMAPSET_TO_TEXT(bms) cstring_to_text(nodeToString(bms))
-#define TEXT_TO_BITMAPSET(str) ((Bitmapset *) 
stringToNode(text_to_cstring(str)))
+
+static Bitmapset *
+text_to_bitmapset(text *arg)
+{
+    Node *node;
+
+    node = stringToNode(text_to_cstring(arg));
+
+    if (node != NULL && !IsA(node, Bitmapset))
+        ereport(ERROR,
+                (errmsg("input is not a Bitmapset")));
+
+    return (Bitmapset *) node;
+}
 
 /*
  * Helper macro to fetch text parameters as Bitmapsets. SQL-NULL means empty
  * set.
  */
 #define PG_ARG_GETBITMAPSET(n) \
-       (PG_ARGISNULL(n) ? NULL : TEXT_TO_BITMAPSET(PG_GETARG_TEXT_PP(n)))
+       (PG_ARGISNULL(n) ? NULL : text_to_bitmapset(PG_GETARG_TEXT_PP(n)))
 
 /*
  * Helper macro to handle converting sets back to text, returning the
-- 
2.47.3

Reply via email to