Repair problems with to_char() overrunning its input string.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 3 Sep 2003 14:59:41 +0000 (14:59 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 3 Sep 2003 14:59:41 +0000 (14:59 +0000)
From Karel Zak.

src/backend/utils/adt/formatting.c

index cc31115fa6c371f160abca078522d8305699fbca..4407e450f9fc551e2aa874df8977ad7e225e03ee 100644 (file)
@@ -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);
    }