v1-0001-Fix-two-defects-with-extended-statistics-for-expr.patch
text/plain
Filename: v1-0001-Fix-two-defects-with-extended-statistics-for-expr.patch
Type: text/plain
Part: 0
Patch
Format: format-patch
Series: patch v1-0001
Subject: Fix two defects with extended statistics for expressions
| File | + | − |
|---|---|---|
| src/backend/statistics/extended_stats.c | 20 | 0 |
| src/backend/utils/adt/selfuncs.c | 5 | 1 |
From 69e219ef17c5100911851dcba093ba211720771d Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 27 Feb 2026 09:36:59 +0900
Subject: [PATCH v1 1/2] Fix two defects with extended statistics for
expressions
This commit addresses two pointer dereferences that are reachable in the
extended statistics code:
1) When building the statistics, the examination of an expression
through examine_attribute() missed the fact that this routine could
return NULL if a typanalyze function triggers its give-up path
(typanalyze callback returns false, no rows or no stats computed). The
build of statistics for MCV, dependencies, ndistinct and expressions
would have tried to look at a NULL pointer, crashing the server.
2) When loading extended statistics for expressions,
statext_expressions_load() has never considered the fact that an element
of the pg_statistic array, storing the statistics of an expression,
could store a NULL entry. Such entries can be generated for example on
an expression whose statistics could not be gathered.
While these conditions cannot be reached with the in-core typanalyze
callbacks, it is possible to trigger these issues with at least a custom
data with a typanalyze callback.
Attribute statistics offer already similar protections than the ones
added in this commit.
---
src/backend/statistics/extended_stats.c | 20 ++++++++++++++++++++
src/backend/utils/adt/selfuncs.c | 6 +++++-
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c
index 3895ed72ef75..334c64985814 100644
--- a/src/backend/statistics/extended_stats.c
+++ b/src/backend/statistics/extended_stats.c
@@ -736,6 +736,16 @@ lookup_var_attr_stats(Bitmapset *attrs, List *exprs,
stats[i] = examine_attribute(expr);
+ /*
+ * If the expression has been found as non-analyzable, give up. We
+ * will not be able to build extended stats with it.
+ */
+ if (stats[i] == NULL)
+ {
+ pfree(stats);
+ return NULL;
+ }
+
/*
* XXX We need tuple descriptor later, and we just grab it from
* stats[0]->tupDesc (see e.g. statext_mcv_build). But as coded
@@ -2396,6 +2406,9 @@ serialize_expr_stats(AnlExprData *exprdata, int nexprs)
/*
* Loads pg_statistic record from expression statistics for expression
* identified by the supplied index.
+ *
+ * Returns the pg_statistic record found, or NULL if there is no statistics
+ * data to use.
*/
HeapTuple
statext_expressions_load(Oid stxoid, bool inh, int idx)
@@ -2424,6 +2437,13 @@ statext_expressions_load(Oid stxoid, bool inh, int idx)
deconstruct_expanded_array(eah);
+ if (eah->dnulls && eah->dnulls[idx])
+ {
+ /* No data found for this expression, give up. */
+ ReleaseSysCache(htup);
+ return NULL;
+ }
+
td = DatumGetHeapTupleHeader(eah->dvalues[idx]);
/* Build a temporary HeapTuple control structure */
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 29fec6555938..587edfc6e839 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -5923,7 +5923,11 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
vardata->statsTuple =
statext_expressions_load(info->statOid, rte->inh, pos);
- vardata->freefunc = ReleaseDummy;
+ /* Nothing to release if no data found */
+ if (vardata->statsTuple != NULL)
+ {
+ vardata->freefunc = ReleaseDummy;
+ }
/*
* Test if user has permission to access all rows from the
--
2.53.0