[PATCH] Fix improper tuple deallocation in import_pg_statist()

yonghao_lee@qq.com <yonghao_lee@qq.com>

From: yonghao_lee <yonghao_lee@qq.com>
To: pgsql-hackers <pgsql-hackers@lists.postgresql.org>
Date: 2026-03-05T00:40:10Z
Lists: pgsql-hackers

Attachments

Hi hackers,


I found a tuple deallocation issue in the import_pg_statistic() function
in src/backend/statistics/extended_stats_funcs.c. The code uses pfree() to release a
HeapTuple, which doesn't properly free the underlying tuple data.


Bug Description:
================


In import_pg_statistic(), after heap_form_tuple() creates a HeapTuple and
heap_copy_tuple_as_datum() copies it to a Datum, the code attempts to free
the temporary HeapTuple using pfree():


&nbsp; &nbsp; pgstup = heap_form_tuple(RelationGetDescr(pgsd), values, nulls);
&nbsp; &nbsp; pgstdat = heap_copy_tuple_as_datum(pgstup, RelationGetDescr(pgsd));
&nbsp; &nbsp; pfree(pgstup);&nbsp; /* <-- BUG: Improper tuple release */


The Problem:
============


HeapTuple is a pointer to HeapTupleData structure, which contains a nested
pointer t_data pointing to the actual tuple header and data:


&nbsp; &nbsp; typedef struct HeapTupleData {
&nbsp; &nbsp; &nbsp; &nbsp; uint32&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t_len;
&nbsp; &nbsp; &nbsp; &nbsp; ItemPointerData t_self;
&nbsp; &nbsp; &nbsp; &nbsp; Oid&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;t_tableOid;
&nbsp; &nbsp; &nbsp; &nbsp; HeapTupleHeader t_data;
&nbsp; &nbsp; } HeapTupleData;


Using pfree(pgstup) only frees the HeapTupleData structure itself
, but leaves the underlying tuple data unfreed.



The Fix:
========


Replace pfree(pgstup) with heap_freetuple(pgstup), which properly frees both
the HeapTupleData structure and the underlying t_data:


&nbsp; &nbsp; -&nbsp; &nbsp; pfree(pgstup);
&nbsp; &nbsp; +&nbsp; &nbsp; heap_freetuple(pgstup);


Patch:
======
---
&nbsp;src/backend/statistics/extended_stats_funcs.c | 2 +-
&nbsp;1 file changed, 1 insertion(+), 1 deletion(-)


diff --git a/src/backend/statistics/extended_stats_funcs.c b/src/backend/statistics/extended_stats_funcs.c
index 0ec77a6..9279904 100644
--- a/src/backend/statistics/extended_stats_funcs.c
+++ b/src/backend/statistics/extended_stats_funcs.c
@@ -1509,7 +1509,7 @@ import_pg_statistic(Relation pgsd, JsonbContainer *cont,
&nbsp;	pgstup = heap_form_tuple(RelationGetDescr(pgsd), values, nulls);
&nbsp;	pgstdat = heap_copy_tuple_as_datum(pgstup, RelationGetDescr(pgsd));
&nbsp;
-	pfree(pgstup);
+	heap_freetuple(pgstup);
&nbsp;
&nbsp;	*pg_statistic_ok = true;
&nbsp;
--


Regards,
Yonghao Lee

Commits

  1. Fix inconsistency with HeapTuple freeing in extended_stats_funcs.c