Silence resource leaks alerts

Started by Ranier Vilela9 months ago6 messages
#1Ranier Vilela
ranier.vf@gmail.com
2 attachment(s)

Hi.

Per Coverity.

Coverity has some alerts about resource leaks.
I think that is good silence.

While it is arguable that this is a false warning, there is a benefit in
moving the initialization of the string buffer, silencing the warnings that
are presented in this case.

1. pg_overexplain.c
2. ruleutils.c

best regards,
Ranier Vilela

Attachments:

postpone_string_buffer_creation_pg_overexplain.patchapplication/octet-stream; name=postpone_string_buffer_creation_pg_overexplain.patchDownload
diff --git a/contrib/pg_overexplain/pg_overexplain.c b/contrib/pg_overexplain/pg_overexplain.c
index afc34ad5f2..595953dc78 100644
--- a/contrib/pg_overexplain/pg_overexplain.c
+++ b/contrib/pg_overexplain/pg_overexplain.c
@@ -738,14 +738,13 @@ overexplain_intlist(const char *qlabel, List *list, ExplainState *es)
 {
 	StringInfoData buf;
 
-	initStringInfo(&buf);
-
 	if (list == NIL)
 	{
 		ExplainPropertyText(qlabel, "none", es);
 		return;
 	}
 
+	initStringInfo(&buf);
 	if (IsA(list, IntList))
 	{
 		foreach_int(i, list)
postpone_string_buffer_creation_ruleutils.patchapplication/octet-stream; name=postpone_string_buffer_creation_ruleutils.patchDownload
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 9e90acedb9..53588218cc 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2940,8 +2940,6 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
 	float4		procost;
 	int			oldlen;
 
-	initStringInfo(&buf);
-
 	/* Look up the function */
 	proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
 	if (!HeapTupleIsValid(proctup))
@@ -2957,6 +2955,8 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
 
 	isfunction = (proc->prokind != PROKIND_PROCEDURE);
 
+	initStringInfo(&buf);
+
 	/*
 	 * We always qualify the function name, to ensure the right function gets
 	 * replaced.
@@ -3614,8 +3614,6 @@ pg_get_function_sqlbody(PG_FUNCTION_ARGS)
 	HeapTuple	proctup;
 	bool		isnull;
 
-	initStringInfo(&buf);
-
 	/* Look up the function */
 	proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
 	if (!HeapTupleIsValid(proctup))
@@ -3628,6 +3626,7 @@ pg_get_function_sqlbody(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 	}
 
+	initStringInfo(&buf);
 	print_function_sqlbody(&buf, proctup);
 
 	ReleaseSysCache(proctup);
#2Michael Paquier
michael@paquier.xyz
In reply to: Ranier Vilela (#1)
Re: Silence resource leaks alerts

On Thu, Apr 10, 2025 at 03:10:02PM -0300, Ranier Vilela wrote:

While it is arguable that this is a false warning, there is a benefit in
moving the initialization of the string buffer, silencing the warnings that
are presented in this case.

1. pg_overexplain.c
2. ruleutils.c

These code paths are far from being critical and the two ones in
ruleutils.c are older, even if it is a practice that had better be
discouraged particularly as initStringInfo() can allocate some memory
for nothing. So it could bloat the current memory context if these
code paths are repeatedly taken.

FWIW, I'm with these changes to delay these initializations as you are
proposing. The RMT has a say about such changes post feature-freeze,
though, even if the one in pg_overexplain.c is new to v18.
--
Michael

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Michael Paquier (#2)
Re: Silence resource leaks alerts

Michael Paquier <michael@paquier.xyz> writes:

On Thu, Apr 10, 2025 at 03:10:02PM -0300, Ranier Vilela wrote:

While it is arguable that this is a false warning, there is a benefit in
moving the initialization of the string buffer, silencing the warnings that
are presented in this case.

1. pg_overexplain.c
2. ruleutils.c

These code paths are far from being critical and the two ones in
ruleutils.c are older, even if it is a practice that had better be
discouraged particularly as initStringInfo() can allocate some memory
for nothing. So it could bloat the current memory context if these
code paths are repeatedly taken.

I don't believe either module ever gets run in a long-lived memory
context. So I think the burden of proof to show that these leaks
are meaningful is on the proposer.

I'm totally not on board with the approach of "if Coverity says this
is a leak then we must fix it". By and large, it's more efficient
for us to leak small allocations and recover them at context reset or
delete than it is to pfree those allocations retail. Sure, if we're
talking about big allocations, or if there will be a lot of such
allocations during the lifetime of the context, we'd better do the
retail pfrees. Sadly, such criteria are outside Coverity's ken.

regards, tom lane

#4Ranier Vilela
ranier.vf@gmail.com
In reply to: Michael Paquier (#2)
Re: Silence resource leaks alerts

Thanks Michael, for looking at this.

Em sex., 11 de abr. de 2025 às 02:09, Michael Paquier <michael@paquier.xyz>
escreveu:

On Thu, Apr 10, 2025 at 03:10:02PM -0300, Ranier Vilela wrote:

While it is arguable that this is a false warning, there is a benefit in
moving the initialization of the string buffer, silencing the warnings

that

are presented in this case.

1. pg_overexplain.c
2. ruleutils.c

These code paths are far from being critical and the two ones in
ruleutils.c are older, even if it is a practice that had better be
discouraged particularly as initStringInfo() can allocate some memory
for nothing. So it could bloat the current memory context if these
code paths are repeatedly taken.

Yeah, it's a bit annoying to do unnecessary work.
Plus a small gain, by delaying memory allocation until when it is actually
needed.

FWIW, I'm with these changes to delay these initializations as you are
proposing.

Thanks.

The RMT has a say about such changes post feature-freeze,
though, even if the one in pg_overexplain.c is new to v18.

I agree.

best regards,
Ranier Vilela

#5Ranier Vilela
ranier.vf@gmail.com
In reply to: Tom Lane (#3)
Re: Silence resource leaks alerts

Em sex., 11 de abr. de 2025 às 02:37, Tom Lane <tgl@sss.pgh.pa.us> escreveu:

Michael Paquier <michael@paquier.xyz> writes:

On Thu, Apr 10, 2025 at 03:10:02PM -0300, Ranier Vilela wrote:

While it is arguable that this is a false warning, there is a benefit in
moving the initialization of the string buffer, silencing the warnings

that

are presented in this case.

1. pg_overexplain.c
2. ruleutils.c

These code paths are far from being critical and the two ones in
ruleutils.c are older, even if it is a practice that had better be
discouraged particularly as initStringInfo() can allocate some memory
for nothing. So it could bloat the current memory context if these
code paths are repeatedly taken.

I don't believe either module ever gets run in a long-lived memory
context. So I think the burden of proof to show that these leaks
are meaningful is on the proposer.

Despite the $subject talking about leaks, the issue in this specific case
is doing unnecessary work.
Get the silencing of these alerts for free.

I'm totally not on board with the approach of "if Coverity says this
is a leak then we must fix it".

I partially agree.
In some cases, it can actually be disastrous.

For example: src/backend/tcop/fastpath.c (line 456)
CID 1608897: (#1 of 1): Resource leak (RESOURCE_LEAK)
10. leaked_storage: Variable abuf going out of scope leaks the storage
abuf.data points to

"Fixing" this leak, causes several errors:

diff --strip-trailing-cr -U3
C:/dll/postgres_dev/postgres_commit/src/test/regress/expected/largeobject_1.out
C:/dll/postgres_dev/postgres_commit/build/testrun/regress/regress/results/largeobject.out
---
C:/dll/postgres_dev/postgres_commit/src/test/regress/expected/largeobject_1.out
2024-10-24 16:40:59.364703100 -0300
+++
C:/dll/postgres_dev/postgres_commit/build/testrun/regress/regress/results/largeobject.out
2025-04-11 08:55:10.085484800 -0300
@@ -37,11 +37,13 @@
 (1 row)
 \lo_unlink 42
+ERROR:  pfree called with invalid pointer 000000C6593FF110 (header
0x000001d03fc52f08)
 \dl
-      Large objects
- ID | Owner | Description
-----+-------+-------------
-(0 rows)
+               Large objects
+ ID |      Owner      |     Description
+----+-----------------+---------------------
+ 42 | regress_lo_user | the ultimate answer
+(1 row)

-- Load a file
CREATE TABLE lotest_stash_values (loid oid, fd integer);
@@ -417,19 +419,354 @@
(1 row)

 \lo_import :filename
+ERROR:  pfree called with invalid pointer 000000C6593FF110 (header
0x000001d03fc529e8)
 \set newloid :LASTOID
 -- just make sure \lo_export does not barf
 \set filename :abs_builddir '/results/lotest2.txt'
 \lo_export :newloid :filename
+ERROR:  pfree called with invalid pointer 000000C6593FF110 (header
0x000001d03fc529e8)
 -- This is a hack to test that export/import are reversible
 -- This uses knowledge about the inner workings of large object mechanism
 -- which should not be used outside it.  This makes it a HACK
 SELECT pageno, data FROM pg_largeobject WHERE loid = (SELECT loid from
lotest_stash_values)
 EXCEPT
 SELECT pageno, data FROM pg_largeobject WHERE loid = :newloid;
- pageno | data
---------+------
-(0 rows)
+ pageno
<cut>

By and large, it's more efficient

for us to leak small allocations and recover them at context reset or
delete than it is to pfree those allocations retail.

As long as you don't allocate memory in advance and unnecessarily.
Even for small amounts, it is an expensive operation.
And compilers are not able to remove it themselves.

Sure, if we're

talking about big allocations, or if there will be a lot of such
allocations during the lifetime of the context, we'd better do the
retail pfrees. Sadly, such criteria are outside Coverity's ken.

Coverity has gotten better and better,
but understanding the complexity in Postgres, for memory usage,
is still far away.

best regards,
Ranier Vilela

#6Ranier Vilela
ranier.vf@gmail.com
In reply to: Ranier Vilela (#4)
1 attachment(s)
Re: Silence resource leaks alerts

Em sex., 11 de abr. de 2025 às 08:27, Ranier Vilela <ranier.vf@gmail.com>
escreveu:

Thanks Michael, for looking at this.

Em sex., 11 de abr. de 2025 às 02:09, Michael Paquier <michael@paquier.xyz>
escreveu:

On Thu, Apr 10, 2025 at 03:10:02PM -0300, Ranier Vilela wrote:

While it is arguable that this is a false warning, there is a benefit in
moving the initialization of the string buffer, silencing the warnings

that

are presented in this case.

1. pg_overexplain.c
2. ruleutils.c

These code paths are far from being critical and the two ones in
ruleutils.c are older, even if it is a practice that had better be
discouraged particularly as initStringInfo() can allocate some memory
for nothing. So it could bloat the current memory context if these
code paths are repeatedly taken.

Yeah, it's a bit annoying to do unnecessary work.
Plus a small gain, by delaying memory allocation until when it is actually
needed.

Attached a new example of moving stringinfo creation, per Coverity.

best regards,
Ranier Vilela

Attachments:

postpone_string_buffer_creation_dblink.patchapplication/octet-stream; name=postpone_string_buffer_creation_dblink.patchDownload
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 092f0753ff..9a5fbbb90c 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -2875,15 +2875,12 @@ get_connect_string(const char *servername)
 	ForeignServer *foreign_server = NULL;
 	UserMapping *user_mapping;
 	ListCell   *cell;
-	StringInfoData buf;
 	ForeignDataWrapper *fdw;
 	AclResult	aclresult;
 	char	   *srvname;
 
 	static const PQconninfoOption *options = NULL;
 
-	initStringInfo(&buf);
-
 	/*
 	 * Get list of valid libpq options.
 	 *
@@ -2908,6 +2905,7 @@ get_connect_string(const char *servername)
 
 	if (foreign_server)
 	{
+		StringInfoData buf;
 		Oid			serverid = foreign_server->serverid;
 		Oid			fdwid = foreign_server->fdwid;
 		Oid			userid = GetUserId();
@@ -2920,6 +2918,8 @@ get_connect_string(const char *servername)
 		if (aclresult != ACLCHECK_OK)
 			aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, foreign_server->servername);
 
+		initStringInfo(&buf);
+
 		/*
 		 * First append hardcoded options needed for SCRAM pass-through, so if
 		 * the user overwrites these options we can ereport on