aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-04-11 12:29:06 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2020-04-11 12:29:06 -0400
commit30ce86367e3eeacfadfc748bf33194eb8fd3c1ba (patch)
tree3bf243bce3a13a808d9d8aae4eab6fe8c3b3021e /src
parent2cab4ad81bcb44ccd6591ed1fb54495c7301b42d (diff)
downloadpostgresql-30ce86367e3eeacfadfc748bf33194eb8fd3c1ba.tar.gz
postgresql-30ce86367e3eeacfadfc748bf33194eb8fd3c1ba.zip
Clear dangling pointer to avoid bogus EXPLAIN printout in a corner case.
ExecReScanHashJoin will destroy the join's hash table if it expects that the inner relation will produce different rows on rescan. Up to now it's not bothered to clear the additional pointer to that hash table that exists in the child HashState node. However, it's possible for the query to terminate without building a fresh hash table (this happens if the outer relation is found to be empty during the final rescan). So we can end with a dangling pointer to a deleted hash table. That was harmless originally, but since 9.0 EXPLAIN ANALYZE has used that pointer to print hash table statistics. In debug builds this reproducibly results in garbage statistics. In non-debug builds there's frequently no ill effects, but in principle one could get wrong EXPLAIN ANALYZE output, or perhaps even a crash if free() has released the hashtable memory back to the OS. To fix, just make sure we clear the additional pointer when destroying the hash table. In problematic cases, EXPLAIN ANALYZE will then print no hashtable statistics (reverting to its pre-9.0 behavior). This isn't ideal, but since the problem manifests only in unusual corner cases, it's hard to justify taking any risks to do better in the back branches. A follow-on patch will improve matters in HEAD. Konstantin Knizhnik and Tom Lane, per diagnosis by Thomas Munro of a trouble report from Alvaro Herrera. Discussion: https://postgr.es/m/20200323165059.GA24950@alvherre.pgsql
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeHashjoin.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 7ca26392297..8b677fbc145 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -988,6 +988,12 @@ ExecReScanHashJoin(HashJoinState *node)
else
{
/* must destroy and rebuild hash table */
+ HashState *hashNode = castNode(HashState, innerPlanState(node));
+
+ /* for safety, be sure to clear child plan node's pointer too */
+ Assert(hashNode->hashtable == node->hj_HashTable);
+ hashNode->hashtable = NULL;
+
ExecHashTableDestroy(node->hj_HashTable);
node->hj_HashTable = NULL;
node->hj_JoinState = HJ_BUILD_HASHTABLE;