From 9089287aa037fdecb5a52cec1926e5ae9569e9f9 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 20 Jul 2023 14:23:46 -0400
Subject: [PATCH] Guard against null plan pointer in CachedPlanIsSimplyValid().

If both the passed-in plan pointer and plansource->gplan are
NULL, CachedPlanIsSimplyValid would think that the plan pointer
is possibly-valid and try to dereference it.  For the one extant
call site in plpgsql, this situation doesn't normally happen
which is why we've not noticed. However, it appears to be possible
if the previous use of the cached plan failed, as per report from
Justin Pryzby.  Add an extra check to prevent crashing.
Back-patch to v13 where this code was added.

Discussion: https://postgr.es/m/ZLlV+STFz1l/WhAQ@telsasoft.com
---
 src/backend/utils/cache/plancache.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 3d3f7a9bea..56c84e1e62 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1440,7 +1440,9 @@ CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan,
 	 * that here we *do* check plansource->is_valid, so as to force plan
 	 * rebuild if that's become false.
 	 */
-	if (!plansource->is_valid || plan != plansource->gplan || !plan->is_valid)
+	if (!plansource->is_valid ||
+		plan == NULL || plan != plansource->gplan ||
+		!plan->is_valid)
 		return false;
 
 	Assert(plan->magic == CACHEDPLAN_MAGIC);