]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix a passel of ancient bugs in to_char(), including two distinct buffer
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 29 Jun 2007 01:52:14 +0000 (01:52 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 29 Jun 2007 01:52:14 +0000 (01:52 +0000)
overruns (neither of which seem likely to be exploitable as security holes,
fortunately, since the provoker can't control the data written).  One of
these is due to choosing to stomp on the output of a called function, which
is bad news in any case; make it treat the called functions' results as
read-only.  Avoid some unnecessary palloc/pfree traffic too; it's not
really helpful to free small temporary objects, and again this is presuming
more than it ought to about the nature of the results of called functions.
Per report from Patrick Welche and additional code-reading by Imad.

src/backend/utils/adt/formatting.c

index 9066776862f1899c87a0d0be888b0290ed88a3cb..a4f420042c053cc4bfb60d40025a7d64e2601bdd 100644 (file)
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------
  * formatting.c
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.69.2.1 2005/03/26 00:42:21 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.69.2.2 2007/06/29 01:52:14 tgl Exp $
  *
  *
  *      Portions Copyright (c) 1999-2003, PostgreSQL Global Development Group
@@ -74,6 +74,7 @@
 #include <unistd.h>
 #include <math.h>
 #include <float.h>
+#include <limits.h>
 
 #include "utils/builtins.h"
 #include "utils/date.h"
  * More is in float.c
  * ----------
  */
-#define MAXFLOATWIDTH  64
-#define MAXDOUBLEWIDTH 128
+#define MAXFLOATWIDTH  60
+#define MAXDOUBLEWIDTH 500
 
 /* ----------
  * External (defined in PgSQL dt.c (timestamp utils))
@@ -1448,7 +1449,7 @@ str_numth(char *dest, char *num, int type)
 }
 
 /* ----------
- * Convert string to upper-string. Input string is modified in place.
+ * Convert string to upper case. Input string is modified in place.
  * ----------
  */
 static char *
@@ -1468,7 +1469,7 @@ str_toupper(char *buff)
 }
 
 /* ----------
- * Convert string to lower-string. Input string is modified in place.
+ * Convert string to lower case. Input string is modified in place.
  * ----------
  */
 static char *
@@ -1996,19 +1997,16 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node, void *data)
                case DCH_TZ:
                        if (flag == TO_CHAR && tmtcTzn(tmtc))
                        {
-                               int                     siz = strlen(tmtcTzn(tmtc));
-
                                if (arg == DCH_TZ)
                                        strcpy(inout, tmtcTzn(tmtc));
                                else
                                {
-                                       char       *p = palloc(siz);
+                                       char       *p = pstrdup(tmtcTzn(tmtc));
 
-                                       strcpy(p, tmtcTzn(tmtc));
                                        strcpy(inout, str_tolower(p));
                                        pfree(p);
                                }
-                               return siz - 1;
+                               return strlen(inout) - 1;
                        }
                        else if (flag == FROM_CHAR)
                                ereport(ERROR,
@@ -3221,7 +3219,7 @@ static char *
 fill_str(char *str, int c, int max)
 {
        memset(str, c, max);
-       *(str + max + 1) = '\0';
+       *(str + max) = '\0';
        return str;
 }
 
@@ -4333,10 +4331,9 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
 #define NUM_TOCHAR_prepare \
 do { \
        len = VARSIZE(fmt) - VARHDRSZ;                                  \
-       if (len <= 0)                                                   \
+       if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ)             \
                return DirectFunctionCall1(textin, CStringGetDatum(""));        \
-       result  = (text *) palloc( (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
-       memset(result, 0,  (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ ); \
+       result  = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ);    \
        format  = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree);              \
 } while (0)
 
@@ -4348,28 +4345,18 @@ do { \
 do { \
        NUM_processor(format, &Num, VARDATA(result),                    \
                numstr, plen, sign, TO_CHAR);                           \
-       pfree(orgnum);                                                  \
                                                                        \
-       if (shouldFree)                                                 \
-               pfree(format);                                          \
+       if (shouldFree)                                 \
+               pfree(format);                          \
                                                                        \
-       /*
-        * for result is allocated max memory, which current format-picture\
-        * needs, now it must be re-allocate to result real size        \
+       /*                                                              \
+        * Convert null-terminated representation of result to standard text. \
+        * The result is usually much bigger than it needs to be, but there \
+        * seems little point in realloc'ing it smaller. \
         */                                                             \
-       if (!(len = strlen(VARDATA(result))))                           \
-       {                                                               \
-               pfree(result);                                          \
-               PG_RETURN_NULL();                                       \
-       }                                                               \
-                                                                       \
-       result_tmp      = result;                                       \
-       result          = (text *) palloc( len + 1 + VARHDRSZ);         \
-                                                                       \
-       strcpy( VARDATA(result), VARDATA(result_tmp));                  \
-       VARATT_SIZEP(result) = len + VARHDRSZ;                          \
-       pfree(result_tmp);                                              \
-} while(0)
+       len = strlen(VARDATA(result));  \
+       VARATT_SIZEP(result) = len + VARHDRSZ;  \
+} while (0)
 
 /* -------------------
  * NUMERIC to_number() (convert string to numeric)
@@ -4391,7 +4378,7 @@ numeric_to_number(PG_FUNCTION_ARGS)
 
        len = VARSIZE(fmt) - VARHDRSZ;
 
-       if (len <= 0)
+       if (len <= 0 || len >= INT_MAX/NUM_MAX_ITEM_SIZ)
                PG_RETURN_NULL();
 
        format = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree);
@@ -4426,8 +4413,7 @@ numeric_to_char(PG_FUNCTION_ARGS)
        text       *fmt = PG_GETARG_TEXT_P(1);
        NUMDesc         Num;
        FormatNode *format;
-       text       *result,
-                          *result_tmp;
+       text       *result;
        bool            shouldFree;
        int                     len = 0,
                                plen = 0,
@@ -4450,7 +4436,6 @@ numeric_to_char(PG_FUNCTION_ARGS)
                numstr = orgnum =
                        int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
                                                                                                   NumericGetDatum(x))));
-               pfree(x);
        }
        else
        {
@@ -4469,9 +4454,6 @@ numeric_to_char(PG_FUNCTION_ARGS)
                        val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
                                                                                                  NumericGetDatum(value),
                                                                                                        NumericGetDatum(x)));
-                       pfree(x);
-                       pfree(a);
-                       pfree(b);
                        Num.pre += Num.multi;
                }
 
@@ -4480,10 +4462,9 @@ numeric_to_char(PG_FUNCTION_ARGS)
                                                                                                Int32GetDatum(Num.post)));
                orgnum = DatumGetCString(DirectFunctionCall1(numeric_out,
                                                                                                         NumericGetDatum(x)));
-               pfree(x);
 
                if (*orgnum == '-')
-               {                                               /* < 0 */
+               {
                        sign = '-';
                        numstr = orgnum + 1;
                }
@@ -4502,13 +4483,10 @@ numeric_to_char(PG_FUNCTION_ARGS)
 
                else if (len > Num.pre)
                {
-                       fill_str(numstr, '#', Num.pre);
+                       numstr = (char *) palloc(Num.pre + Num.post + 2);
+                       fill_str(numstr, '#', Num.pre + Num.post + 1);
                        *(numstr + Num.pre) = '.';
-                       fill_str(numstr + 1 + Num.pre, '#', Num.post);
                }
-
-               if (IS_MULTI(&Num))
-                       pfree(val);
        }
 
        NUM_TOCHAR_finish;
@@ -4526,8 +4504,7 @@ int4_to_char(PG_FUNCTION_ARGS)
        text       *fmt = PG_GETARG_TEXT_P(1);
        NUMDesc         Num;
        FormatNode *format;
-       text       *result,
-                          *result_tmp;
+       text       *result;
        bool            shouldFree;
        int                     len = 0,
                                plen = 0,
@@ -4555,40 +4532,34 @@ int4_to_char(PG_FUNCTION_ARGS)
                        orgnum = DatumGetCString(DirectFunctionCall1(int4out,
                                                                                                  Int32GetDatum(value)));
                }
-               len = strlen(orgnum);
 
                if (*orgnum == '-')
-               {                                               /* < 0 */
+               {
                        sign = '-';
-                       --len;
+                       orgnum++;
                }
                else
                        sign = '+';
+               len = strlen(orgnum);
 
                if (Num.post)
                {
-                       int                     i;
-
                        numstr = (char *) palloc(len + Num.post + 2);
-                       strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0));
+                       strcpy(numstr, orgnum);
                        *(numstr + len) = '.';
-
-                       for (i = len + 1; i <= len + Num.post; i++)
-                               *(numstr + i) = '0';
+                       memset(numstr + len + 1, '0', Num.post);
                        *(numstr + len + Num.post + 1) = '\0';
-                       pfree(orgnum);
-                       orgnum = numstr;
                }
                else
-                       numstr = orgnum + (*orgnum == '-' ? 1 : 0);
+                       numstr = orgnum;
 
                if (Num.pre > len)
                        plen = Num.pre - len;
                else if (len > Num.pre)
                {
-                       fill_str(numstr, '#', Num.pre);
+                       numstr = (char *) palloc(Num.pre + Num.post + 2);
+                       fill_str(numstr, '#', Num.pre + Num.post + 1);
                        *(numstr + Num.pre) = '.';
-                       fill_str(numstr + 1 + Num.pre, '#', Num.post);
                }
        }
 
@@ -4607,8 +4578,7 @@ int8_to_char(PG_FUNCTION_ARGS)
        text       *fmt = PG_GETARG_TEXT_P(1);
        NUMDesc         Num;
        FormatNode *format;
-       text       *result,
-                          *result_tmp;
+       text       *result;
        bool            shouldFree;
        int                     len = 0,
                                plen = 0,
@@ -4642,40 +4612,34 @@ int8_to_char(PG_FUNCTION_ARGS)
 
                orgnum = DatumGetCString(DirectFunctionCall1(int8out,
                                                                                                  Int64GetDatum(value)));
-               len = strlen(orgnum);
 
                if (*orgnum == '-')
-               {                                               /* < 0 */
+               {
                        sign = '-';
-                       --len;
+                       orgnum++;
                }
                else
                        sign = '+';
+               len = strlen(orgnum);
 
                if (Num.post)
                {
-                       int                     i;
-
                        numstr = (char *) palloc(len + Num.post + 2);
-                       strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0));
+                       strcpy(numstr, orgnum);
                        *(numstr + len) = '.';
-
-                       for (i = len + 1; i <= len + Num.post; i++)
-                               *(numstr + i) = '0';
+                       memset(numstr + len + 1, '0', Num.post);
                        *(numstr + len + Num.post + 1) = '\0';
-                       pfree(orgnum);
-                       orgnum = numstr;
                }
                else
-                       numstr = orgnum + (*orgnum == '-' ? 1 : 0);
+                       numstr = orgnum;
 
                if (Num.pre > len)
                        plen = Num.pre - len;
                else if (len > Num.pre)
                {
-                       fill_str(numstr, '#', Num.pre);
+                       numstr = (char *) palloc(Num.pre + Num.post + 2);
+                       fill_str(numstr, '#', Num.pre + Num.post + 1);
                        *(numstr + Num.pre) = '.';
-                       fill_str(numstr + 1 + Num.pre, '#', Num.post);
                }
        }
 
@@ -4694,8 +4658,7 @@ float4_to_char(PG_FUNCTION_ARGS)
        text       *fmt = PG_GETARG_TEXT_P(1);
        NUMDesc         Num;
        FormatNode *format;
-       text       *result,
-                          *result_tmp;
+       text       *result;
        bool            shouldFree;
        int                     len = 0,
                                plen = 0,
@@ -4754,9 +4717,9 @@ float4_to_char(PG_FUNCTION_ARGS)
 
                else if (len > Num.pre)
                {
-                       fill_str(numstr, '#', Num.pre);
+                       numstr = (char *) palloc(Num.pre + Num.post + 2);
+                       fill_str(numstr, '#', Num.pre + Num.post + 1);
                        *(numstr + Num.pre) = '.';
-                       fill_str(numstr + 1 + Num.pre, '#', Num.post);
                }
        }
 
@@ -4775,8 +4738,7 @@ float8_to_char(PG_FUNCTION_ARGS)
        text       *fmt = PG_GETARG_TEXT_P(1);
        NUMDesc         Num;
        FormatNode *format;
-       text       *result,
-                          *result_tmp;
+       text       *result;
        bool            shouldFree;
        int                     len = 0,
                                plen = 0,
@@ -4833,9 +4795,9 @@ float8_to_char(PG_FUNCTION_ARGS)
 
                else if (len > Num.pre)
                {
-                       fill_str(numstr, '#', Num.pre);
+                       numstr = (char *) palloc(Num.pre + Num.post + 2);
+                       fill_str(numstr, '#', Num.pre + Num.post + 1);
                        *(numstr + Num.pre) = '.';
-                       fill_str(numstr + 1 + Num.pre, '#', Num.post);
                }
        }