From 025d2832d7df80a6cdb3e87360dcf53ff64eb62e Mon Sep 17 00:00:00 2001 From: Ewan Young Date: Thu, 2 Jul 2026 17:48:15 +0800 Subject: [PATCH] Fix crash in satisfies_hash_partition() with NULL variadic array satisfies_hash_partition() is not strict, so it can be reached with a NULL variadic array argument, e.g. SELECT satisfies_hash_partition('hp'::regclass, 1, 0, VARIADIC NULL::int[]); When the call is variadic, the function fetches the argument with PG_GETARG_ARRAYTYPE_P(3) without first checking for NULL, which dereferences a NULL pointer and crashes the server. Commit f3b0897a1213 fixed a set of related NULL-handling problems in this function but overlooked the NULL variadic array case. Fix by returning false when the call is variadic and the array argument is NULL, mirroring how NULL parent OID, modulus, and remainder are handled. The NULL check must be gated on the call being variadic: for a non-variadic call, a NULL fourth argument is a legitimate NULL value for the first partitioning column (this is how the hash-partition CHECK constraint routes rows with NULL key columns), and must continue to be accepted rather than turned into a false result. Back-patch to all supported branches, as f3b0897a1213 was. --- src/backend/partitioning/partbounds.c | 12 ++++++++++-- src/test/regress/expected/hash_part.out | 8 ++++++++ src/test/regress/sql/hash_part.sql | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c index 6fb150a8763..754d3077624 100644 --- a/src/backend/partitioning/partbounds.c +++ b/src/backend/partitioning/partbounds.c @@ -4781,8 +4781,16 @@ satisfies_hash_partition(PG_FUNCTION_ARGS) ColumnsHashData *my_extra; uint64 rowHash = 0; - /* Return false if the parent OID, modulus, or remainder is NULL. */ - if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) + /* + * Return false if the parent OID, modulus, or remainder is NULL, or if the + * call is variadic and the variadic array argument itself is NULL. (In a + * non-variadic call, an individual NULL key value is legal and handled + * below; likewise NULL elements of a non-NULL variadic array. But a NULL + * variadic array has no elements to deconstruct, so treat it like the + * other NULL fixed arguments.) + */ + if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2) || + (get_fn_expr_variadic(fcinfo->flinfo) && PG_ARGISNULL(3))) PG_RETURN_BOOL(false); parentId = PG_GETARG_OID(0); modulus = PG_GETARG_INT32(1); diff --git a/src/test/regress/expected/hash_part.out b/src/test/regress/expected/hash_part.out index cb39161f867..ce58b20b382 100644 --- a/src/test/regress/expected/hash_part.out +++ b/src/test/regress/expected/hash_part.out @@ -95,6 +95,14 @@ ERROR: number of partitioning columns (2) does not match number of partition ke SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0, variadic array[now(), now()]); ERROR: column 1 of the partition key has type "integer", but supplied value is of type "timestamp with time zone" +-- NULL variadic array must not crash; should be false +SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0, + variadic NULL::int[]); + satisfies_hash_partition +-------------------------- + f +(1 row) + -- check satisfies_hash_partition passes correct collation create table text_hashp (a text) partition by hash (a); create table text_hashp0 partition of text_hashp for values with (modulus 2, remainder 0); diff --git a/src/test/regress/sql/hash_part.sql b/src/test/regress/sql/hash_part.sql index 6e2c1f21bfc..279b780cd48 100644 --- a/src/test/regress/sql/hash_part.sql +++ b/src/test/regress/sql/hash_part.sql @@ -75,6 +75,10 @@ SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0, SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0, variadic array[now(), now()]); +-- NULL variadic array must not crash; should be false +SELECT satisfies_hash_partition('mcinthash'::regclass, 4, 0, + variadic NULL::int[]); + -- check satisfies_hash_partition passes correct collation create table text_hashp (a text) partition by hash (a); create table text_hashp0 partition of text_hashp for values with (modulus 2, remainder 0); -- 2.47.3