From 7d58f2342bd3d2f0474207b63a3a548c29e20a9e Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Wed, 27 Dec 2023 03:34:23 +0200 Subject: [PATCH] REALLOCATE_BITMAPSETS manual compile-time option This option forces each bitmapset modification to reallocate bitmapset. This is useful for debugging hangling pointers to bitmapset's. 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 | 77 ++++++++++++++++++++++++++++++++++ src/include/pg_config_manual.h | 6 +++ 2 files changed, 83 insertions(+) diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c index 1627922ef7..e13ecaa155 100644 --- a/src/backend/nodes/bitmapset.c +++ b/src/backend/nodes/bitmapset.c @@ -263,6 +263,7 @@ bms_intersect(const Bitmapset *a, const Bitmapset *b) /* Handle cases where either input is NULL */ if (a == NULL || b == NULL) return NULL; + /* Identify shorter and longer input; copy the shorter one */ if (a->nwords <= b->nwords) { @@ -798,8 +799,15 @@ bms_add_member(Bitmapset *a, int x) { int oldnwords = a->nwords; int i; +#ifdef REALLOCATE_BITMAPSETS + Bitmapset *tmp = a; + a = (Bitmapset *) palloc(BITMAPSET_SIZE(wordnum + 1)); + memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords)); + pfree(tmp); +#else a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(wordnum + 1)); +#endif a->nwords = wordnum + 1; /* zero out the enlarged portion */ i = oldnwords; @@ -808,6 +816,16 @@ bms_add_member(Bitmapset *a, int x) a->words[i] = 0; } while (++i < a->nwords); } +#ifdef REALLOCATE_BITMAPSETS + else + { + Bitmapset *tmp = a; + + a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords)); + memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords)); + pfree(tmp); + } +#endif a->words[wordnum] |= ((bitmapword) 1 << bitnum); return a; @@ -825,6 +843,9 @@ bms_del_member(Bitmapset *a, int x) { int wordnum, bitnum; +#ifdef REALLOCATE_BITMAPSETS + Bitmapset *tmp = a; +#endif if (x < 0) elog(ERROR, "negative bitmapset member not allowed"); @@ -836,6 +857,12 @@ bms_del_member(Bitmapset *a, int x) wordnum = WORDNUM(x); bitnum = BITNUM(x); +#ifdef REALLOCATE_BITMAPSETS + a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords)); + memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords)); + pfree(tmp); +#endif + /* member can't exist. Return 'a' unmodified */ if (unlikely(wordnum >= a->nwords)) return a; @@ -889,6 +916,13 @@ bms_add_members(Bitmapset *a, const Bitmapset *b) } else { +#ifdef REALLOCATE_BITMAPSETS + Bitmapset *tmp = a; + + a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords)); + memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords)); + pfree(tmp); +#endif result = a; other = b; } @@ -941,9 +975,16 @@ bms_add_range(Bitmapset *a, int lower, int upper) { int oldnwords = a->nwords; int i; +#ifdef REALLOCATE_BITMAPSETS + Bitmapset *tmp = a; + a = (Bitmapset *) palloc(BITMAPSET_SIZE(uwordnum + 1)); + memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords)); + pfree(tmp); +#else /* ensure we have enough words to store the upper bit */ a = (Bitmapset *) repalloc(a, BITMAPSET_SIZE(uwordnum + 1)); +#endif a->nwords = uwordnum + 1; /* zero out the enlarged portion */ i = oldnwords; @@ -992,6 +1033,12 @@ bms_int_members(Bitmapset *a, const Bitmapset *b) int lastnonzero; int shortlen; int i; +#ifdef REALLOCATE_BITMAPSETS + Bitmapset *tmp = a; +#endif + + Assert(a == NULL || IsA(a, Bitmapset)); + Assert(b == NULL || IsA(b, Bitmapset)); Assert(a == NULL || IsA(a, Bitmapset)); Assert(b == NULL || IsA(b, Bitmapset)); @@ -1004,6 +1051,13 @@ bms_int_members(Bitmapset *a, const Bitmapset *b) pfree(a); return NULL; } + +#ifdef REALLOCATE_BITMAPSETS + a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords)); + memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords)); + pfree(tmp); +#endif + /* Intersect b into a; we need never copy */ shortlen = Min(a->nwords, b->nwords); lastnonzero = -1; @@ -1035,6 +1089,9 @@ Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b) { int i; +#ifdef REALLOCATE_BITMAPSETS + Bitmapset *tmp = a; +#endif Assert(a == NULL || (IsA(a, Bitmapset) && a->words[a->nwords - 1] != 0)); Assert(b == NULL || (IsA(b, Bitmapset) && b->words[b->nwords - 1] != 0)); @@ -1044,6 +1101,13 @@ bms_del_members(Bitmapset *a, const Bitmapset *b) return NULL; if (b == NULL) return a; + +#ifdef REALLOCATE_BITMAPSETS + a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords)); + memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords)); + pfree(tmp); +#endif + /* Remove b's bits from a; we need never copy */ if (a->nwords > b->nwords) { @@ -1096,6 +1160,12 @@ bms_join(Bitmapset *a, Bitmapset *b) Bitmapset *other; int otherlen; int i; +#ifdef REALLOCATE_BITMAPSETS + Bitmapset *tmp = a; +#endif + + Assert(a == NULL || IsA(a, Bitmapset)); + Assert(b == NULL || IsA(b, Bitmapset)); Assert(a == NULL || IsA(a, Bitmapset)); Assert(b == NULL || IsA(b, Bitmapset)); @@ -1105,6 +1175,13 @@ bms_join(Bitmapset *a, Bitmapset *b) return b; if (b == NULL) return a; + +#ifdef REALLOCATE_BITMAPSETS + a = (Bitmapset *) palloc(BITMAPSET_SIZE(tmp->nwords)); + memcpy(a, tmp, BITMAPSET_SIZE(tmp->nwords)); + pfree(tmp); +#endif + /* Identify shorter and longer input; use longer one as result */ if (a->nwords < b->nwords) { diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 8a6e67a445..16c383ba7f 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -335,6 +335,12 @@ */ /* #define COPY_PARSE_PLAN_TREES */ +/* + * Define this to force Bitmapset reallocation on each modification. Helps + * to find hangling pointers to Bitmapset's. + */ +/* #define REALLOCATE_BITMAPSETS */ + /* * Define this to force all parse and plan trees to be passed through * outfuncs.c/readfuncs.c, to facilitate catching errors and omissions in