From ae3ff7adf79f5e2bcf6ce856cdf32abf0fe67468 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 24 Nov 2007 21:20:07 +0000
Subject: [PATCH] Fix (I think) broken usage of MultiByteToWideChar.  I had
 missed the subtlety that this function only returns a null terminator if it's
 fed input that includes one; which, in the usage here, it's not. This
 probably fixes bugs reported by Thomas Haegi.

---
 src/backend/tsearch/ts_locale.c | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/src/backend/tsearch/ts_locale.c b/src/backend/tsearch/ts_locale.c
index acec56bfeb2..8a34cc5269a 100644
--- a/src/backend/tsearch/ts_locale.c
+++ b/src/backend/tsearch/ts_locale.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tsearch/ts_locale.c,v 1.4 2007/11/15 21:14:38 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tsearch/ts_locale.c,v 1.5 2007/11/24 21:20:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,7 +23,7 @@
  * wchar2char --- convert wide characters to multibyte format
  *
  * This has the same API as the standard wcstombs() function; in particular,
- * tolen is the maximum number of bytes to store at *to, and *from should be
+ * tolen is the maximum number of bytes to store at *to, and *from must be
  * zero-terminated.  The output will be zero-terminated iff there is room.
  */
 size_t
@@ -73,21 +73,28 @@ char2wchar(wchar_t *to, size_t tolen, const char *from, size_t fromlen)
 	{
 		int			r;
 
-		r = MultiByteToWideChar(CP_UTF8, 0, from, fromlen, to, tolen);
-
-		if (r <= 0)
+		/* stupid Microsloth API does not work for zero-length input */
+		if (fromlen == 0)
+			r = 0;
+		else
 		{
-			pg_verifymbstr(from, fromlen, false);
-			ereport(ERROR,
-					(errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE),
-					 errmsg("invalid multibyte character for locale"),
-					 errhint("The server's LC_CTYPE locale is probably incompatible with the database encoding.")));
+			r = MultiByteToWideChar(CP_UTF8, 0, from, fromlen, to, tolen - 1);
+
+			if (r <= 0)
+			{
+				/* see notes in oracle_compat.c about error reporting */
+				pg_verifymbstr(from, fromlen, false);
+				ereport(ERROR,
+						(errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE),
+						 errmsg("invalid multibyte character for locale"),
+						 errhint("The server's LC_CTYPE locale is probably incompatible with the database encoding.")));
+			}
 		}
 
-		Assert(r <= tolen);
+		Assert(r < tolen);
+		to[r] = 0;
 
-		/* Microsoft counts the zero terminator in the result */
-		return r - 1;
+		return r;
 	}
 #endif   /* WIN32 */
 
-- 
GitLab