From fa98a86f65cc2d71cbef5caa063f12c66233238c Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 28 May 2007 16:43:24 +0000
Subject: [PATCH] Tweak the code in a couple of places to try to deliver more
 user-friendly error messages when a single COPY line is too long for us to
 handle.  Per example from Johann Spies.

---
 src/backend/lib/stringinfo.c   | 19 ++++++++------
 src/backend/utils/mb/mbutils.c | 48 +++++++++++++++++++++++++++-------
 2 files changed, 50 insertions(+), 17 deletions(-)

diff --git a/src/backend/lib/stringinfo.c b/src/backend/lib/stringinfo.c
index b0854ddc43b..a35f30b933b 100644
--- a/src/backend/lib/stringinfo.c
+++ b/src/backend/lib/stringinfo.c
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	  $PostgreSQL: pgsql/src/backend/lib/stringinfo.c,v 1.45 2007/03/03 19:32:54 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/lib/stringinfo.c,v 1.46 2007/05/28 16:43:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -234,14 +234,17 @@ enlargeStringInfo(StringInfo str, int needed)
 	int			newlen;
 
 	/*
-	 * Guard against ridiculous "needed" values, which can occur if we're fed
-	 * bogus data.	Without this, we can get an overflow or infinite loop in
-	 * the following.
+	 * Guard against out-of-range "needed" values.  Without this, we can get
+	 * an overflow or infinite loop in the following.
 	 */
-	if (needed < 0 ||
-		((Size) needed) >= (MaxAllocSize - (Size) str->len))
-		elog(ERROR, "invalid string enlargement request size %d",
-			 needed);
+	if (needed < 0)				/* should not happen */
+		elog(ERROR, "invalid string enlargement request size: %d", needed);
+	if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
+		ereport(ERROR,
+				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+				 errmsg("out of memory"),
+				 errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
+						   str->len, needed)));
 
 	needed += str->len + 1;		/* total space required now */
 
diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c
index cee6807d66c..a466073ca0a 100644
--- a/src/backend/utils/mb/mbutils.c
+++ b/src/backend/utils/mb/mbutils.c
@@ -4,7 +4,7 @@
  * (currently mule internal code (mic) is used)
  * Tatsuo Ishii
  *
- * $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.62 2007/02/27 23:48:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.63 2007/05/28 16:43:24 tgl Exp $
  */
 #include "postgres.h"
 
@@ -15,6 +15,17 @@
 #include "utils/memutils.h"
 #include "utils/syscache.h"
 
+/*
+ * When converting strings between different encodings, we assume that space
+ * for converted result is 4-to-1 growth in the worst case. The rate for
+ * currently supported encoding pairs are within 3 (SJIS JIS X0201 half width
+ * kanna -> UTF8 is the worst case).  So "4" should be enough for the moment.
+ *
+ * Note that this is not the same as the maximum character width in any
+ * particular encoding.
+ */
+#define MAX_CONVERSION_GROWTH  4
+
 /*
  * We handle for actual FE and BE encoding setting encoding-identificator
  * and encoding-name too. It prevent searching and conversion from encoding
@@ -207,15 +218,14 @@ pg_get_client_encoding_name(void)
  * conversion function is chosen from the pg_conversion system catalog
  * marked as "default". If it is not found in the schema search path,
  * it's taken from pg_catalog schema. If it even is not in the schema,
- * warn and returns src. We cannot raise an error, since it will cause
- * an infinit loop in error message sending.
+ * warn and return src.
  *
  * In the case of no conversion, src is returned.
  *
- * XXX We assume that storage for converted result is 4-to-1 growth in
- * the worst case. The rate for currently supported encoding pares are within 3
- * (SJIS JIS X0201 half width kanna -> UTF8 is the worst case).
- * So "4" should be enough for the moment.
+ * Note: we try to avoid raising error, since that could get us into
+ * infinite recursion when this function is invoked during error message
+ * sending.  It should be OK to raise error for overlength strings though,
+ * since the recursion will come with a shorter message.
  */
 unsigned char *
 pg_do_encoding_conversion(unsigned char *src, int len,
@@ -260,7 +270,17 @@ pg_do_encoding_conversion(unsigned char *src, int len,
 		return src;
 	}
 
-	result = palloc(len * 4 + 1);
+	/*
+	 * Allocate space for conversion result, being wary of integer overflow
+	 */
+	if ((Size) len >= (MaxAllocSize / (Size) MAX_CONVERSION_GROWTH))
+		ereport(ERROR,
+				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+				 errmsg("out of memory"),
+				 errdetail("String of %d bytes is too long for encoding conversion.",
+						   len)));
+
+	result = palloc(len * MAX_CONVERSION_GROWTH + 1);
 
 	OidFunctionCall5(proc,
 					 Int32GetDatum(src_encoding),
@@ -458,7 +478,17 @@ perform_default_encoding_conversion(const char *src, int len, bool is_client_to_
 	if (flinfo == NULL)
 		return (char *) src;
 
-	result = palloc(len * 4 + 1);
+	/*
+	 * Allocate space for conversion result, being wary of integer overflow
+	 */
+	if ((Size) len >= (MaxAllocSize / (Size) MAX_CONVERSION_GROWTH))
+		ereport(ERROR,
+				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+				 errmsg("out of memory"),
+				 errdetail("String of %d bytes is too long for encoding conversion.",
+						   len)));
+
+	result = palloc(len * MAX_CONVERSION_GROWTH + 1);
 
 	FunctionCall5(flinfo,
 				  Int32GetDatum(src_encoding),
-- 
GitLab