pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
[PATCH] Reject nonpositive Bloom filter element estimates
2+ messages / 2 participants
[nested] [flat]

* [PATCH] Reject nonpositive Bloom filter element estimates
@ 2026-09-18 10:31  CharSyam <charsyam@gmail.com>
  0 siblings, 1 reply; 2+ messages in thread

From: CharSyam @ 2026-09-18 10:31 UTC (permalink / raw)
  To: pgsql-hackers <pgsql-hackers@lists.postgresql.org>

Hi, Hackers.

bloom_create() currently accepts a zero total_elems estimate.  This
causes optimal_k() to divide by zero and then convert infinity to int,
which is undefined behavior.

The attached patch rejects nonpositive estimates before the calculation.
It also performs the bitset size multiplication as unsigned arithmetic
to avoid signed overflow for very large positive estimates, and adds a
regression test for the zero case.

The affected source and test module compile successfully, and
git diff --check passes.

Regards,
DaeMyung Kang

Attachments:

  [application/octet-stream] v1-0001-Reject-nonpositive-Bloom-filter-element-estimates.patch (2.3K, ../../CAMrLSE671yN2u4zeo2pnUY2rm=arYfb0rVSr5v+9m9t9vL802w@mail.gmail.com/2-v1-0001-Reject-nonpositive-Bloom-filter-element-estimates.patch)
  download | inline diff:
diff --git a/src/backend/lib/bloomfilter.c b/src/backend/lib/bloomfilter.c
index 73b3768a172..b24c932ab8f 100644
--- a/src/backend/lib/bloomfilter.c
+++ b/src/backend/lib/bloomfilter.c
@@ -91,6 +91,9 @@ bloom_create(int64 total_elems, int bloom_work_mem, uint64 seed)
 	uint64		bitset_bytes;
 	uint64		bitset_bits;

+	if (total_elems <= 0)
+		elog(ERROR, "total number of elements must be greater than zero");
+
 	/*
 	 * Aim for two bytes per element; this is sufficient to get a false
 	 * positive rate below 1%, independent of the size of the bitset or total
@@ -98,7 +101,8 @@ bloom_create(int64 total_elems, int bloom_work_mem, uint64 seed)
 	 * the next lowest power of two turns out to be a significant drop, the
 	 * false positive rate still won't exceed 2% in almost all cases.
 	 */
-	bitset_bytes = Min(bloom_work_mem * UINT64CONST(1024), total_elems * 2);
+	bitset_bytes = Min(bloom_work_mem * UINT64CONST(1024),
+					   (uint64) total_elems * 2);
 	bitset_bytes = Max(1024 * 1024, bitset_bytes);

 	/*
diff --git a/src/test/modules/test_bloomfilter/expected/test_bloomfilter.out b/src/test/modules/test_bloomfilter/expected/test_bloomfilter.out
index 21c068867d6..137eb4f2140 100644
--- a/src/test/modules/test_bloomfilter/expected/test_bloomfilter.out
+++ b/src/test/modules/test_bloomfilter/expected/test_bloomfilter.out
@@ -9,6 +9,12 @@ SELECT test_bloomfilter(power => 23,
  
 (1 row)

+-- A Bloom filter cannot be sized for an empty set.
+SELECT test_bloomfilter(power => 23,
+    nelements => 0,
+    seed => 0,
+    tests => 1);
+ERROR:  total number of elements must be greater than zero
 -- Equivalent "10 bits per element" tests for all possible bitset sizes:
 --
 -- SELECT test_bloomfilter(24, 1677722)
diff --git a/src/test/modules/test_bloomfilter/sql/test_bloomfilter.sql b/src/test/modules/test_bloomfilter/sql/test_bloomfilter.sql
index 9ec159ce404..5a94c95eb2a 100644
--- a/src/test/modules/test_bloomfilter/sql/test_bloomfilter.sql
+++ b/src/test/modules/test_bloomfilter/sql/test_bloomfilter.sql
@@ -6,6 +6,12 @@ SELECT test_bloomfilter(power => 23,
     seed => -1,
     tests => 1);

+-- A Bloom filter cannot be sized for an empty set.
+SELECT test_bloomfilter(power => 23,
+    nelements => 0,
+    seed => 0,
+    tests => 1);
+
 -- Equivalent "10 bits per element" tests for all possible bitset sizes:
 --
 -- SELECT test_bloomfilter(24, 1677722)


^ permalink  raw  reply  [nested|flat] 2+ messages in thread

* Re: [PATCH] Reject nonpositive Bloom filter element estimates
@ 2026-09-18 14:41  Nathan Bossart <nathandbossart@gmail.com>
  parent: CharSyam <charsyam@gmail.com>
  0 siblings, 0 replies; 2+ messages in thread

From: Nathan Bossart @ 2026-09-18 14:41 UTC (permalink / raw)
  To: CharSyam <charsyam@gmail.com>; +Cc: pgsql-hackers <pgsql-hackers@lists.postgresql.org>

On Fri, Sep 18, 2026 at 07:31:04PM +0900, CharSyam wrote:
> bloom_create() currently accepts a zero total_elems estimate.  This
> causes optimal_k() to divide by zero and then convert infinity to int,
> which is undefined behavior.
> 
> The attached patch rejects nonpositive estimates before the calculation.

For backend functions like this, I don't see much value in checking the
arguments like this.  It seems highly unlikely that any caller will provide
a total_elems setting of 0.  Maybe an assertion would be more appropriate,
but IMHO we can still do without it.

> It also performs the bitset size multiplication as unsigned arithmetic
> to avoid signed overflow for very large positive estimates, and adds a
> regression test for the zero case.

Again, it seems highly unlikely that any caller will provide a total_elems
value even close to 4.6 quintillion.

-- 
nathan






^ permalink  raw  reply  [nested|flat] 2+ messages in thread


end of thread, other threads:[~2026-09-18 14:41 UTC | newest]

Thread overview: 2+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18 10:31 [PATCH] Reject nonpositive Bloom filter element estimates CharSyam <charsyam@gmail.com>
2026-09-18 14:41 ` Nathan Bossart <nathandbossart@gmail.com>

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox