From 5840b893732d38c513b447b16adf8449dcbe3228 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 3 Sep 2003 14:59:41 +0000
Subject: [PATCH] Repair problems with to_char() overrunning its input string.
 From Karel Zak.

---
 src/backend/utils/adt/formatting.c | 125 ++++++++++++++++-------------
 1 file changed, 68 insertions(+), 57 deletions(-)

diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index cc31115fa6c..4407e450f9f 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------
  * formatting.c
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.67 2003/08/25 16:13:27 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.68 2003/09/03 14:59:41 tgl Exp $
  *
  *
  *	 Portions Copyright (c) 1999-2003, PostgreSQL Global Development Group
@@ -1294,6 +1294,16 @@ DCH_processor(FormatNode *node, char *inout, int flag, void *data)
 
 	for (n = node, s = inout; n->type != NODE_TYPE_END; n++)
 	{
+		if (flag == FROM_CHAR && *s=='\0')
+			/*
+			 * The input string is shorter than format picture, 
+			 * so it's good time to break this loop...
+			 * 
+			 * Note: this isn't relevant for TO_CHAR mode, beacuse 
+			 *       it use 'inout' allocated by format picture length.
+			 */
+			break;
+
 		if (n->type == NODE_TYPE_ACTION)
 		{
 			int			len;
@@ -1328,9 +1338,8 @@ DCH_processor(FormatNode *node, char *inout, int flag, void *data)
 				}
 			}
 		}
-
+		
 		++s;					/* ! */
-
 	}
 
 	if (flag == TO_CHAR)
@@ -2715,10 +2724,10 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt)
 {
 	FormatNode *format;
 	struct tm  *tm = NULL;
-	char	   *str_fmt,
-			   *result;
-	bool		incache;
-	int			len = VARSIZE(fmt) - VARHDRSZ;
+	char	   *fmt_str,
+		   *result;
+	bool	incache;
+	int	fmt_len = VARSIZE(fmt) - VARHDRSZ;
 
 	tm = tmtcTm(tmtc);
 	tm->tm_wday = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1) % 7;
@@ -2727,29 +2736,28 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt)
 	/*
 	 * Convert fmt to C string
 	 */
-	str_fmt = (char *) palloc(len + 1);
-	memcpy(str_fmt, VARDATA(fmt), len);
-	*(str_fmt + len) = '\0';
+	fmt_str = (char *) palloc(fmt_len + 1);
+	memcpy(fmt_str, VARDATA(fmt), fmt_len);
+	*(fmt_str + fmt_len) = '\0';
 
 	/*
 	 * Allocate result
 	 */
-	result = palloc((len * DCH_MAX_ITEM_SIZ) + 1);
+	result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
 
 	/*
 	 * Allocate new memory if format picture is bigger than static cache
-	 * and not use cache (call parser always) - incache=FALSE show this
-	 * variant
+	 * and not use cache (call parser always) 
 	 */
-	if (len > DCH_CACHE_SIZE)
+	if (fmt_len > DCH_CACHE_SIZE)
 	{
-		format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
+		format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
 		incache = FALSE;
 
-		parse_format(format, str_fmt, DCH_keywords,
+		parse_format(format, fmt_str, DCH_keywords,
 					 DCH_suff, DCH_index, DCH_TYPE, NULL);
 
-		(format + len)->type = NODE_TYPE_END;	/* Paranoia? */
+		(format + fmt_len)->type = NODE_TYPE_END;	/* Paranoia? */
 
 	}
 	else
@@ -2758,25 +2766,24 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt)
 		 * Use cache buffers
 		 */
 		DCHCacheEntry *ent;
-
 		incache = TRUE;
 
-		if ((ent = DCH_cache_search(str_fmt)) == NULL)
+		if ((ent = DCH_cache_search(fmt_str)) == NULL)
 		{
 
-			ent = DCH_cache_getnew(str_fmt);
+			ent = DCH_cache_getnew(fmt_str);
 
 			/*
 			 * Not in the cache, must run parser and save a new
 			 * format-picture to the cache.
 			 */
-			parse_format(ent->format, str_fmt, DCH_keywords,
+			parse_format(ent->format, fmt_str, DCH_keywords,
 						 DCH_suff, DCH_index, DCH_TYPE, NULL);
 
-			(ent->format + len)->type = NODE_TYPE_END;	/* Paranoia? */
+			(ent->format + fmt_len)->type = NODE_TYPE_END;	/* Paranoia? */
 
 #ifdef DEBUG_TO_FROM_CHAR
-			/* dump_node(ent->format, len); */
+			/* dump_node(ent->format, fmt_len); */
 			/* dump_index(DCH_keywords, DCH_index);  */
 #endif
 		}
@@ -2788,22 +2795,27 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt)
 	if (!incache)
 		pfree(format);
 
-	pfree(str_fmt);
+	pfree(fmt_str);
 
 	/*
 	 * for result is allocated max memory, which current format-picture
 	 * needs, now it allocate result with real size
 	 */
-	if (!(len = strlen(result)))
-		pfree(result);
-	else
+	if (result && *result)
 	{
-		text	   *res = (text *) palloc(len + 1 + VARHDRSZ);
+		int len = strlen(result);
+	
+		if (len)
+		{
+			text	   *res = (text *) palloc(len + 1 + VARHDRSZ);
 
-		memcpy(VARDATA(res), result, len);
-		VARATT_SIZEP(res) = len + VARHDRSZ;
-		return res;
+			memcpy(VARDATA(res), result, len);
+			VARATT_SIZEP(res) = len + VARHDRSZ;
+			pfree(result);
+			return res;
+		}
 	}
+	pfree(result);
 	return NULL;
 }
 
@@ -2953,39 +2965,39 @@ do_to_timestamp(text *date_txt, text *fmt,
 {
 	FormatNode *format;
 	TmFromChar	tmfc;
-	bool		incache;
-	char	   *str;
-	char	   *date_str;
-	int			len,
-				date_len;
+	int		fmt_len;
 
 	ZERO_tm(tm);
 	*fsec = 0;
 
 	ZERO_tmfc(&tmfc);
 
-	len = VARSIZE(fmt) - VARHDRSZ;
+	fmt_len = VARSIZE(fmt) - VARHDRSZ;
 
-	if (len)
+	if (fmt_len)
 	{
-		str = (char *) palloc(len + 1);
-		memcpy(str, VARDATA(fmt), len);
-		*(str + len) = '\0';
+		int date_len;
+		char *fmt_str;
+		char *date_str;
+		bool incache;
+		
+		fmt_str = (char *) palloc(fmt_len + 1);
+		memcpy(fmt_str, VARDATA(fmt), fmt_len);
+		*(fmt_str + fmt_len) = '\0';
 
 		/*
 		 * Allocate new memory if format picture is bigger than static
-		 * cache and not use cache (call parser always) - incache=FALSE
-		 * show this variant
+		 * cache and not use cache (call parser always)
 		 */
-		if (len > DCH_CACHE_SIZE)
+		if (fmt_len > DCH_CACHE_SIZE)
 		{
-			format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
+			format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
 			incache = FALSE;
 
-			parse_format(format, str, DCH_keywords,
+			parse_format(format, fmt_str, DCH_keywords,
 						 DCH_suff, DCH_index, DCH_TYPE, NULL);
 
-			(format + len)->type = NODE_TYPE_END;		/* Paranoia? */
+			(format + fmt_len)->type = NODE_TYPE_END;		/* Paranoia? */
 		}
 		else
 		{
@@ -2993,24 +3005,23 @@ do_to_timestamp(text *date_txt, text *fmt,
 			 * Use cache buffers
 			 */
 			DCHCacheEntry *ent;
+			incache = TRUE;
 
-			incache = 0;
-
-			if ((ent = DCH_cache_search(str)) == NULL)
+			if ((ent = DCH_cache_search(fmt_str)) == NULL)
 			{
 
-				ent = DCH_cache_getnew(str);
+				ent = DCH_cache_getnew(fmt_str);
 
 				/*
 				 * Not in the cache, must run parser and save a new
 				 * format-picture to the cache.
 				 */
-				parse_format(ent->format, str, DCH_keywords,
+				parse_format(ent->format, fmt_str, DCH_keywords,
 							 DCH_suff, DCH_index, DCH_TYPE, NULL);
 
-				(ent->format + len)->type = NODE_TYPE_END;		/* Paranoia? */
+				(ent->format + fmt_len)->type = NODE_TYPE_END;		/* Paranoia? */
 #ifdef DEBUG_TO_FROM_CHAR
-				/* dump_node(ent->format, len); */
+				/* dump_node(ent->format, fmt_len); */
 				/* dump_index(DCH_keywords, DCH_index); */
 #endif
 			}
@@ -3021,7 +3032,7 @@ do_to_timestamp(text *date_txt, text *fmt,
 		 * Call action for each node in FormatNode tree
 		 */
 #ifdef DEBUG_TO_FROM_CHAR
-		/* dump_node(format, len); */
+		/* dump_node(format, fmt_len); */
 #endif
 
 		/*
@@ -3035,8 +3046,8 @@ do_to_timestamp(text *date_txt, text *fmt,
 		DCH_processor(format, date_str, FROM_CHAR, (void *) &tmfc);
 
 		pfree(date_str);
-		pfree(str);
-		if (incache)
+		pfree(fmt_str);
+		if (!incache)
 			pfree(format);
 	}
 
-- 
GitLab