Add asserts to bimapset manipulation functions
authorAlexander Korotkov <akorotkov@postgresql.org>
Wed, 27 Dec 2023 01:34:12 +0000 (03:34 +0200)
committerAlexander Korotkov <akorotkov@postgresql.org>
Wed, 27 Dec 2023 01:57:57 +0000 (03:57 +0200)
New asserts validate that arguments are really bitmapsets.  This should help
to early detect accesses to dangling pointers.

Discussion: https://postgr.es/m/CAMbWs4_wJthNtYBL%2BSsebpgF-5L2r5zFFk6xYbS0A78GKOTFHw%40mail.gmail.com
Reviewed-by: Richard Guo, Andres Freund, Ashutosh Bapat, Andrei Lepikhov
src/backend/nodes/bitmapset.c

index 704879f56605048c23b61482f62b7c50f81c6317..1627922ef7ad1877f123d03d74d9b518ab2433e1 100644 (file)
@@ -84,6 +84,7 @@ bms_copy(const Bitmapset *a)
 
        if (a == NULL)
                return NULL;
+       Assert(IsA(a, Bitmapset));
        size = BITMAPSET_SIZE(a->nwords);
        result = (Bitmapset *) palloc(size);
        memcpy(result, a, size);
@@ -98,8 +99,8 @@ bms_equal(const Bitmapset *a, const Bitmapset *b)
 {
        int                     i;
 
-       Assert(a == NULL || a->words[a->nwords - 1] != 0);
-       Assert(b == NULL || b->words[b->nwords - 1] != 0);
+       Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+       Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
 
        /* Handle cases where either input is NULL */
        if (a == NULL)
@@ -139,8 +140,8 @@ bms_compare(const Bitmapset *a, const Bitmapset *b)
 {
        int                     i;
 
-       Assert(a == NULL || a->words[a->nwords - 1] != 0);
-       Assert(b == NULL || b->words[b->nwords - 1] != 0);
+       Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+       Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
 
        /* Handle cases where either input is NULL */
        if (a == NULL)
@@ -215,6 +216,9 @@ bms_union(const Bitmapset *a, const Bitmapset *b)
        int                     otherlen;
        int                     i;
 
+       Assert(a == NULL || IsA(a, Bitmapset));
+       Assert(b == NULL || IsA(b, Bitmapset));
+
        /* Handle cases where either input is NULL */
        if (a == NULL)
                return bms_copy(b);
@@ -253,6 +257,9 @@ bms_intersect(const Bitmapset *a, const Bitmapset *b)
        int                     resultlen;
        int                     i;
 
+       Assert(a == NULL || IsA(a, Bitmapset));
+       Assert(b == NULL || IsA(b, Bitmapset));
+
        /* Handle cases where either input is NULL */
        if (a == NULL || b == NULL)
                return NULL;
@@ -299,8 +306,8 @@ bms_difference(const Bitmapset *a, const Bitmapset *b)
        Bitmapset  *result;
        int                     i;
 
-       Assert(a == NULL || a->words[a->nwords - 1] != 0);
-       Assert(b == NULL || b->words[b->nwords - 1] != 0);
+       Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+       Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
 
        /* Handle cases where either input is NULL */
        if (a == NULL)
@@ -308,6 +315,8 @@ bms_difference(const Bitmapset *a, const Bitmapset *b)
        if (b == NULL)
                return bms_copy(a);
 
+       Assert(IsA(a, Bitmapset) && IsA(b, Bitmapset));
+
        /*
         * In Postgres' usage, an empty result is a very common case, so it's
         * worth optimizing for that by testing bms_nonempty_difference().  This
@@ -364,8 +373,8 @@ bms_is_subset(const Bitmapset *a, const Bitmapset *b)
 {
        int                     i;
 
-       Assert(a == NULL || a->words[a->nwords - 1] != 0);
-       Assert(b == NULL || b->words[b->nwords - 1] != 0);
+       Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+       Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
 
        /* Handle cases where either input is NULL */
        if (a == NULL)
@@ -373,6 +382,8 @@ bms_is_subset(const Bitmapset *a, const Bitmapset *b)
        if (b == NULL)
                return false;
 
+       Assert(IsA(a, Bitmapset) && IsA(b, Bitmapset));
+
        /* 'a' can't be a subset of 'b' if it contains more words */
        if (a->nwords > b->nwords)
                return false;
@@ -399,8 +410,8 @@ bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
        int                     shortlen;
        int                     i;
 
-       Assert(a == NULL || a->words[a->nwords - 1] != 0);
-       Assert(b == NULL || b->words[b->nwords - 1] != 0);
+       Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+       Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
 
        /* Handle cases where either input is NULL */
        if (a == NULL)
@@ -411,6 +422,9 @@ bms_subset_compare(const Bitmapset *a, const Bitmapset *b)
        }
        if (b == NULL)
                return BMS_SUBSET2;
+
+       Assert(IsA(a, Bitmapset) && IsA(b, Bitmapset));
+
        /* Check common words */
        result = BMS_EQUAL;                     /* status so far */
        shortlen = Min(a->nwords, b->nwords);
@@ -467,6 +481,9 @@ bms_is_member(int x, const Bitmapset *a)
                elog(ERROR, "negative bitmapset member not allowed");
        if (a == NULL)
                return false;
+
+       Assert(IsA(a, Bitmapset));
+
        wordnum = WORDNUM(x);
        bitnum = BITNUM(x);
        if (wordnum >= a->nwords)
@@ -495,6 +512,8 @@ bms_member_index(Bitmapset *a, int x)
        if (!bms_is_member(x, a))
                return -1;
 
+       Assert(IsA(a, Bitmapset));
+
        wordnum = WORDNUM(x);
        bitnum = BITNUM(x);
 
@@ -529,6 +548,9 @@ bms_overlap(const Bitmapset *a, const Bitmapset *b)
        int                     shortlen;
        int                     i;
 
+       Assert(a == NULL || IsA(a, Bitmapset));
+       Assert(b == NULL || IsA(b, Bitmapset));
+
        /* Handle cases where either input is NULL */
        if (a == NULL || b == NULL)
                return false;
@@ -553,6 +575,8 @@ bms_overlap_list(const Bitmapset *a, const List *b)
        int                     wordnum,
                                bitnum;
 
+       Assert(a == NULL || IsA(a, Bitmapset));
+
        if (a == NULL || b == NIL)
                return false;
 
@@ -582,8 +606,8 @@ bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
 {
        int                     i;
 
-       Assert(a == NULL || a->words[a->nwords - 1] != 0);
-       Assert(b == NULL || b->words[b->nwords - 1] != 0);
+       Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+       Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
 
        /* Handle cases where either input is NULL */
        if (a == NULL)
@@ -617,6 +641,9 @@ bms_singleton_member(const Bitmapset *a)
 
        if (a == NULL)
                elog(ERROR, "bitmapset is empty");
+
+       Assert(IsA(a, Bitmapset));
+
        nwords = a->nwords;
        wordnum = 0;
        do
@@ -657,6 +684,7 @@ bms_get_singleton_member(const Bitmapset *a, int *member)
 
        if (a == NULL)
                return false;
+       Assert(IsA(a, Bitmapset));
        nwords = a->nwords;
        wordnum = 0;
        do
@@ -690,6 +718,7 @@ bms_num_members(const Bitmapset *a)
 
        if (a == NULL)
                return 0;
+       Assert(IsA(a, Bitmapset));
        nwords = a->nwords;
        wordnum = 0;
        do
@@ -717,6 +746,7 @@ bms_membership(const Bitmapset *a)
 
        if (a == NULL)
                return BMS_EMPTY_SET;
+       Assert(IsA(a, Bitmapset));
        nwords = a->nwords;
        wordnum = 0;
        do
@@ -759,6 +789,7 @@ bms_add_member(Bitmapset *a, int x)
                elog(ERROR, "negative bitmapset member not allowed");
        if (a == NULL)
                return bms_make_singleton(x);
+       Assert(IsA(a, Bitmapset));
        wordnum = WORDNUM(x);
        bitnum = BITNUM(x);
 
@@ -799,6 +830,9 @@ bms_del_member(Bitmapset *a, int x)
                elog(ERROR, "negative bitmapset member not allowed");
        if (a == NULL)
                return NULL;
+
+       Assert(IsA(a, Bitmapset));
+
        wordnum = WORDNUM(x);
        bitnum = BITNUM(x);
 
@@ -839,6 +873,9 @@ bms_add_members(Bitmapset *a, const Bitmapset *b)
        int                     otherlen;
        int                     i;
 
+       Assert(a == NULL || IsA(a, Bitmapset));
+       Assert(b == NULL || IsA(b, Bitmapset));
+
        /* Handle cases where either input is NULL */
        if (a == NULL)
                return bms_copy(b);
@@ -884,6 +921,8 @@ bms_add_range(Bitmapset *a, int lower, int upper)
                                ushiftbits,
                                wordnum;
 
+       Assert(a == NULL || IsA(a, Bitmapset));
+
        /* do nothing if nothing is called for, without further checking */
        if (upper < lower)
                return a;
@@ -954,6 +993,9 @@ bms_int_members(Bitmapset *a, const Bitmapset *b)
        int                     shortlen;
        int                     i;
 
+       Assert(a == NULL || IsA(a, Bitmapset));
+       Assert(b == NULL || IsA(b, Bitmapset));
+
        /* Handle cases where either input is NULL */
        if (a == NULL)
                return NULL;
@@ -994,8 +1036,8 @@ bms_del_members(Bitmapset *a, const Bitmapset *b)
 {
        int                     i;
 
-       Assert(a == NULL || a->words[a->nwords - 1] != 0);
-       Assert(b == NULL || b->words[b->nwords - 1] != 0);
+       Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0));
+       Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0));
 
        /* Handle cases where either input is NULL */
        if (a == NULL)
@@ -1055,6 +1097,9 @@ bms_join(Bitmapset *a, Bitmapset *b)
        int                     otherlen;
        int                     i;
 
+       Assert(a == NULL || IsA(a, Bitmapset));
+       Assert(b == NULL || IsA(b, Bitmapset));
+
        /* Handle cases where either input is NULL */
        if (a == NULL)
                return b;
@@ -1109,6 +1154,8 @@ bms_next_member(const Bitmapset *a, int prevbit)
        int                     wordnum;
        bitmapword      mask;
 
+       Assert(a == NULL || IsA(a, Bitmapset));
+
        if (a == NULL)
                return -2;
        nwords = a->nwords;
@@ -1168,6 +1215,8 @@ bms_prev_member(const Bitmapset *a, int prevbit)
        int                     ushiftbits;
        bitmapword      mask;
 
+       Assert(a == NULL || IsA(a, Bitmapset));
+
        /*
         * If set is NULL or if there are no more bits to the right then we've
         * nothing to do.