Subject: A few pg_locale.c fixes

From: Jeff Davis <[email-masked]>
Date: Wed, 28 Jan 2026 11:37:13 -0800

Attached patches.

Problems found with AI assistance. Patches by me.

Regards,
	Jeff Davis

From f4fd755be542add500aabc23b4255b9ee3631873 Mon Sep 17 00:00:00 2001
From: Jeff Davis <[email-masked]>
Date: Tue, 27 Jan 2026 13:39:55 -0800
Subject: [PATCH v1 1/3] Fix memory leaks in pg_locale_libc.c.

---
 src/backend/utils/adt/pg_locale_libc.c | 30 +++++++++++++-------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/src/backend/utils/adt/pg_locale_libc.c b/src/backend/utils/adt/pg_locale_libc.c
index 2f96e889595..78f6ea161a0 100644
--- a/src/backend/utils/adt/pg_locale_libc.c
+++ b/src/backend/utils/adt/pg_locale_libc.c
@@ -527,11 +527,11 @@ strlower_libc_mb(char *dest, size_t destsize, const char *src, ssize_t srclen,
 
 	result_size = wchar2char(result, workspace, max_size + 1, loc);
 
-	if (result_size + 1 > destsize)
-		return result_size;
-
-	memcpy(dest, result, result_size);
-	dest[result_size] = '\0';
+	if (destsize >= result_size + 1)
+	{
+		memcpy(dest, result, result_size);
+		dest[result_size] = '\0';
+	}
 
 	pfree(workspace);
 	pfree(result);
@@ -638,11 +638,11 @@ strtitle_libc_mb(char *dest, size_t destsize, const char *src, ssize_t srclen,
 
 	result_size = wchar2char(result, workspace, max_size + 1, loc);
 
-	if (result_size + 1 > destsize)
-		return result_size;
-
-	memcpy(dest, result, result_size);
-	dest[result_size] = '\0';
+	if (destsize >= result_size + 1)
+	{
+		memcpy(dest, result, result_size);
+		dest[result_size] = '\0';
+	}
 
 	pfree(workspace);
 	pfree(result);
@@ -725,11 +725,11 @@ strupper_libc_mb(char *dest, size_t destsize, const char *src, ssize_t srclen,
 
 	result_size = wchar2char(result, workspace, max_size + 1, loc);
 
-	if (result_size + 1 > destsize)
-		return result_size;
-
-	memcpy(dest, result, result_size);
-	dest[result_size] = '\0';
+	if (destsize >= result_size + 1)
+	{
+		memcpy(dest, result, result_size);
+		dest[result_size] = '\0';
+	}
 
 	pfree(workspace);
 	pfree(result);
-- 
2.43.0

From 1922a118576f9be73018447b6e5531e6571484de Mon Sep 17 00:00:00 2001
From: Jeff Davis <[email-masked]>
Date: Tue, 27 Jan 2026 13:50:22 -0800
Subject: [PATCH v1 2/3] Fix memory leaks in pg_locale_icu.c.

---
 src/backend/utils/adt/pg_locale_icu.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/backend/utils/adt/pg_locale_icu.c b/src/backend/utils/adt/pg_locale_icu.c
index 88f86ab18a3..352b4c3885f 100644
--- a/src/backend/utils/adt/pg_locale_icu.c
+++ b/src/backend/utils/adt/pg_locale_icu.c
@@ -597,6 +597,8 @@ make_icu_collator(const char *iculocstr, const char *icurules)
 							iculocstr, icurules, u_errorName(status))));
 		}
 
+		pfree(my_rules);
+		pfree(all_rules);
 		return collator_all_rules;
 	}
 }
@@ -1106,6 +1108,9 @@ strnxfrm_prefix_icu(char *dest, size_t destsize,
 				(errmsg("sort key generation failed: %s",
 						u_errorName(status))));
 
+	if (buf != sbuf)
+		pfree(buf);
+
 	return result_bsize;
 }
 
-- 
2.43.0

From ec6a98973bfca4fd6be8538ec45119c286140082 Mon Sep 17 00:00:00 2001
From: Jeff Davis <[email-masked]>
Date: Tue, 27 Jan 2026 14:30:19 -0800
Subject: [PATCH v1 3/3] pg_locale.c: Clean up srclen == -1.

No callers currently specify -1, but the API should handle it
correctly to mean a NUL-termianted string.
---
 src/backend/utils/adt/pg_locale_icu.c  | 1 +
 src/backend/utils/adt/pg_locale_libc.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/src/backend/utils/adt/pg_locale_icu.c b/src/backend/utils/adt/pg_locale_icu.c
index 352b4c3885f..4659a50cbb8 100644
--- a/src/backend/utils/adt/pg_locale_icu.c
+++ b/src/backend/utils/adt/pg_locale_icu.c
@@ -703,6 +703,7 @@ downcase_ident_icu(char *dst, size_t dstsize, const char *src,
 
 	libc_lower = lt && (pg_database_encoding_max_length() == 1);
 
+	srclen = (srclen >= 0) ? srclen : strlen(src);
 	for (i = 0; i < srclen && i < dstsize; i++)
 	{
 		unsigned char ch = (unsigned char) src[i];
diff --git a/src/backend/utils/adt/pg_locale_libc.c b/src/backend/utils/adt/pg_locale_libc.c
index 78f6ea161a0..5feec161a43 100644
--- a/src/backend/utils/adt/pg_locale_libc.c
+++ b/src/backend/utils/adt/pg_locale_libc.c
@@ -329,6 +329,7 @@ downcase_ident_libc_sb(char *dst, size_t dstsize, const char *src,
 	locale_t	loc = locale->lt;
 	int			i;
 
+	srclen = (srclen >= 0) ? srclen : strlen(src);
 	for (i = 0; i < srclen && i < dstsize; i++)
 	{
 		unsigned char ch = (unsigned char) src[i];
-- 
2.43.0