new warnings with clang-21 / how const is Datum

Started by Peter Eisentraut4 months ago3 messages
#1Peter Eisentraut
peter@eisentraut.org

clang-21 shows some new warnings:

../src/backend/access/common/toast_internals.c:296:33: error: variable
'chunk_data' is uninitialized when passed as a const pointer argument
here [-Werror,-Wuninitialized-const-pointer]
296 | t_values[2] = PointerGetDatum(&chunk_data);

../src/backend/access/gist/gistutil.c:207:28: error: variable 'attrsize'
is uninitialized when passed as a const pointer argument here
[-Werror,-Wuninitialized-const-pointer]
207 |
PointerGetDatum(&attrsize));
|
^~~~~~~~
../src/backend/access/gist/gistutil.c:276:27: error: variable 'dstsize'
is uninitialized when passed as a const pointer argument here
[-Werror,-Wuninitialized-const-pointer]
276 |
PointerGetDatum(&dstsize));
|
^~~~~~~

The first one is easily fixed by re-arranging the code a bit.

The other two indicate more fundamental problems. The gist API uses
these arguments to pass back information; these pointers do not in fact
point to a const object.

This possibly means that the change

commit c8b2ef05f48
Author: Peter Eisentraut <peter@eisentraut.org>
Date: Tue Sep 27 20:47:07 2022

Convert *GetDatum() and DatumGet*() macros to inline functions

that made PointerGetDatum() look like

static inline Datum
PointerGetDatum(const void *X)

was mistaken in adding the const qualifier.

We could remove that qualifier (this would propagate to several other
functions built on top of PointerGetDatum()), but then there will be
complaints from the other side:

static const TableAmRoutine heapam_methods = {

PG_RETURN_POINTER(&heapam_methods);

Then the question is, which one of these should be considered the outlier?

We could remove the const qualifications from the API and stick an
unconstify() around &heapam_methods.

Or we could maybe make a new function PointerNonConstGetDatum() that we
use for exceptional cases like the gist API.

There is a related issue that I have been researching for some time. It
seems intuitively correct that the string passed into a data type input
function should not be modified by that function. And so the relevant
functions could use const qualifiers like

extern Datum InputFunctionCall(FmgrInfo *flinfo, const char *str, ...);

which they currently do not.

There are a some places in the code where const strings get passed into
some *InputFunctionCall() functions and have their const qualifications
rudely cast away, which seems unsatisfactory.

Overall, the question to what extent fmgr functions are allowed to
modify objects pointed to by their input arguments doesn't seem to be
addressed anywhere.

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#1)
Re: new warnings with clang-21 / how const is Datum

Peter Eisentraut <peter@eisentraut.org> writes:

Overall, the question to what extent fmgr functions are allowed to
modify objects pointed to by their input arguments doesn't seem to be
addressed anywhere.

I think it's generally understood that an fmgr function must not
modify pass-by-reference inputs, because they could easily be
pointing directly into a heap tuple in a shared buffer. The
exception is functions that participate in custom APIs where the
presence of output argument(s) is explicitly documented.

One question that statement leaves unanswered is whether datatype
input functions qualify as a "custom API". I'd vote not (ie they
shouldn't modify their input strings) unless we find exceptions.

So that suggests that the use of non-const pointer Datums should be
the outlier.

regards, tom lane

#3Peter Eisentraut
peter@eisentraut.org
In reply to: Peter Eisentraut (#1)
2 attachment(s)
Re: new warnings with clang-21 / how const is Datum

On 01.09.25 08:47, Peter Eisentraut wrote:

clang-21 shows some new warnings:

../src/backend/access/common/toast_internals.c:296:33: error: variable
'chunk_data' is uninitialized when passed as a const pointer argument
here [-Werror,-Wuninitialized-const-pointer]
  296 |         t_values[2] = PointerGetDatum(&chunk_data);

../src/backend/access/gist/gistutil.c:207:28: error: variable 'attrsize'
is uninitialized when passed as a const pointer argument here [-Werror,-
Wuninitialized-const-pointer]
  207 |                 PointerGetDatum(&attrsize));
      |                                  ^~~~~~~~
../src/backend/access/gist/gistutil.c:276:27: error: variable 'dstsize'
is uninitialized when passed as a const pointer argument here [-Werror,-
Wuninitialized-const-pointer]
  276 |  PointerGetDatum(&dstsize));
      |                   ^~~~~~~

Here is a quick-fix patch for this. It silences these warnings by
initializing the respective variables first. This is already done
similarly in nearby code. This can be backpatched to PG16, where these
warnings began.

The second patch is a bit of a more extensive code rearrangement to make
the need for the workaround in the first patch go away. This would be
for master only.

Attachments:

0001-Silence-compiler-warning-on-clang-21.patchtext/plain; charset=UTF-8; name=0001-Silence-compiler-warning-on-clang-21.patchDownload
From cb71953c5e4ce5203bb4867711e68ff2891ad3b8 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 8 Sep 2025 12:38:06 +0200
Subject: [PATCH 1/2] Silence compiler warning on clang 21

Clang 21 shows some new compiler warnings, for example:

warning: variable 'dstsize' is uninitialized when passed as a const pointer argument here [-Wuninitialized-const-pointer]

The fix is to initialize the variables when they are defined.  This is
similar to, for example, the existing situation in gistKeyIsEQ().

Discussion: https://www.postgresql.org/message-id/flat/6604ad6e-5934-43ac-8590-15113d6ae4b1%40eisentraut.org
---
 src/backend/access/common/toast_internals.c | 2 +-
 src/backend/access/gist/gistutil.c          | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index a1d0eed8953..75e908c2e80 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -135,7 +135,7 @@ toast_save_datum(Relation rel, Datum value,
 		char		data[TOAST_MAX_CHUNK_SIZE + VARHDRSZ];
 		/* ensure union is aligned well enough: */
 		int32		align_it;
-	}			chunk_data;
+	}			chunk_data = {0};	/* silence compiler warning */
 	int32		chunk_size;
 	int32		chunk_seq = 0;
 	char	   *data_p;
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index c0aa7d0222f..cdc4ab3151b 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -157,7 +157,7 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len,
 {
 	int			i;
 	GistEntryVector *evec;
-	int			attrsize;
+	int			attrsize = 0;	/* silence compiler warning */
 
 	evec = (GistEntryVector *) palloc((len + 2) * sizeof(GISTENTRY) + GEVHDRSZ);
 
@@ -242,7 +242,7 @@ gistMakeUnionKey(GISTSTATE *giststate, int attno,
 		char		padding[2 * sizeof(GISTENTRY) + GEVHDRSZ];
 	}			storage;
 	GistEntryVector *evec = &storage.gev;
-	int			dstsize;
+	int			dstsize = 0;	/* silence compiler warning */
 
 	evec->n = 2;
 

base-commit: 8191e0c16a0373f851a9f5a8112e3aec105b5276
-- 
2.51.0

0002-Some-stylistic-improvements-in-toast_save_datum.patchtext/plain; charset=UTF-8; name=0002-Some-stylistic-improvements-in-toast_save_datum.patchDownload
From a4e9c43d5fa9642adcd2efa0f7db8efa45328236 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 8 Sep 2025 13:24:29 +0200
Subject: [PATCH 2/2] Some stylistic improvements in toast_save_datum()

Move some variables to a smaller scope.  Initialize chunk_data before
storing a pointer to it; this avoids compiler warnings on clang21, or
respectively us having to work around it by initializing it to zero
before the variable is used.

Discussion: https://www.postgresql.org/message-id/flat/6604ad6e-5934-43ac-8590-15113d6ae4b1%40eisentraut.org
---
 src/backend/access/common/toast_internals.c | 39 +++++++++------------
 1 file changed, 16 insertions(+), 23 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 75e908c2e80..81dbd67c725 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -121,22 +121,10 @@ toast_save_datum(Relation rel, Datum value,
 {
 	Relation	toastrel;
 	Relation   *toastidxs;
-	HeapTuple	toasttup;
 	TupleDesc	toasttupDesc;
-	Datum		t_values[3];
-	bool		t_isnull[3];
 	CommandId	mycid = GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
-	union
-	{
-		struct varlena hdr;
-		/* this is to make the union big enough for a chunk: */
-		char		data[TOAST_MAX_CHUNK_SIZE + VARHDRSZ];
-		/* ensure union is aligned well enough: */
-		int32		align_it;
-	}			chunk_data = {0};	/* silence compiler warning */
-	int32		chunk_size;
 	int32		chunk_seq = 0;
 	char	   *data_p;
 	int32		data_todo;
@@ -289,21 +277,23 @@ toast_save_datum(Relation rel, Datum value,
 		}
 	}
 
-	/*
-	 * Initialize constant parts of the tuple data
-	 */
-	t_values[0] = ObjectIdGetDatum(toast_pointer.va_valueid);
-	t_values[2] = PointerGetDatum(&chunk_data);
-	t_isnull[0] = false;
-	t_isnull[1] = false;
-	t_isnull[2] = false;
-
 	/*
 	 * Split up the item into chunks
 	 */
 	while (data_todo > 0)
 	{
-		int			i;
+		HeapTuple	toasttup;
+		Datum		t_values[3];
+		bool		t_isnull[3] = {0};
+		union
+		{
+			struct varlena hdr;
+			/* this is to make the union big enough for a chunk: */
+			char		data[TOAST_MAX_CHUNK_SIZE + VARHDRSZ];
+			/* ensure union is aligned well enough: */
+			int32		align_it;
+		}			chunk_data;
+		int32		chunk_size;
 
 		CHECK_FOR_INTERRUPTS();
 
@@ -315,9 +305,12 @@ toast_save_datum(Relation rel, Datum value,
 		/*
 		 * Build a tuple and store it
 		 */
+		t_values[0] = ObjectIdGetDatum(toast_pointer.va_valueid);
 		t_values[1] = Int32GetDatum(chunk_seq++);
 		SET_VARSIZE(&chunk_data, chunk_size + VARHDRSZ);
 		memcpy(VARDATA(&chunk_data), data_p, chunk_size);
+		t_values[2] = PointerGetDatum(&chunk_data);
+
 		toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull);
 
 		heap_insert(toastrel, toasttup, mycid, options, NULL);
@@ -333,7 +326,7 @@ toast_save_datum(Relation rel, Datum value,
 		 * Note also that there had better not be any user-created index on
 		 * the TOAST table, since we don't bother to update anything else.
 		 */
-		for (i = 0; i < num_indexes; i++)
+		for (int i = 0; i < num_indexes; i++)
 		{
 			/* Only index relations marked as ready can be updated */
 			if (toastidxs[i]->rd_index->indisready)
-- 
2.51.0