1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-01 14:21:49 +03:00

Fix a passel of ancient bugs in to_char(), including two distinct buffer

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.
This commit is contained in:
Tom Lane 2007-06-29 01:51:56 +00:00
parent ed368c1b8e
commit 2fc2402566

View File

@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- /* -----------------------------------------------------------------------
* formatting.c * formatting.c
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.101.2.3 2006/09/04 19:29:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.101.2.4 2007/06/29 01:51:56 tgl Exp $
* *
* *
* Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group
@ -73,6 +73,7 @@
#include <unistd.h> #include <unistd.h>
#include <math.h> #include <math.h>
#include <float.h> #include <float.h>
#include <limits.h>
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/date.h" #include "utils/date.h"
@ -107,8 +108,8 @@
* More is in float.c * More is in float.c
* ---------- * ----------
*/ */
#define MAXFLOATWIDTH 64 #define MAXFLOATWIDTH 60
#define MAXDOUBLEWIDTH 128 #define MAXDOUBLEWIDTH 500
/* ---------- /* ----------
* External (defined in PgSQL datetime.c (timestamp utils)) * External (defined in PgSQL datetime.c (timestamp utils))
@ -1477,7 +1478,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 * static char *
@ -1497,7 +1498,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 * static char *
@ -2002,19 +2003,16 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
INVALID_FOR_INTERVAL; INVALID_FOR_INTERVAL;
if (is_to_char && tmtcTzn(tmtc)) if (is_to_char && tmtcTzn(tmtc))
{ {
int siz = strlen(tmtcTzn(tmtc));
if (arg == DCH_TZ) if (arg == DCH_TZ)
strcpy(inout, tmtcTzn(tmtc)); strcpy(inout, tmtcTzn(tmtc));
else else
{ {
char *p = palloc(siz); char *p = pstrdup(tmtcTzn(tmtc));
strcpy(p, tmtcTzn(tmtc));
strcpy(inout, str_tolower(p)); strcpy(inout, str_tolower(p));
pfree(p); pfree(p);
} }
return siz; return strlen(inout);
} }
else if (!is_to_char) else if (!is_to_char)
ereport(ERROR, ereport(ERROR,
@ -3225,7 +3223,7 @@ static char *
fill_str(char *str, int c, int max) fill_str(char *str, int c, int max)
{ {
memset(str, c, max); memset(str, c, max);
*(str + max + 1) = '\0'; *(str + max) = '\0';
return str; return str;
} }
@ -4422,10 +4420,9 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
#define NUM_TOCHAR_prepare \ #define NUM_TOCHAR_prepare \
do { \ do { \
len = VARSIZE(fmt) - VARHDRSZ; \ len = VARSIZE(fmt) - VARHDRSZ; \
if (len <= 0) \ if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ) \
return DirectFunctionCall1(textin, CStringGetDatum("")); \ return DirectFunctionCall1(textin, CStringGetDatum("")); \
result = (text *) palloc( (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \ result = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
memset(result, 0, (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ ); \
format = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree); \ format = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree); \
} while (0) } while (0)
@ -4435,30 +4432,19 @@ do { \
*/ */
#define NUM_TOCHAR_finish \ #define NUM_TOCHAR_finish \
do { \ do { \
NUM_processor(format, &Num, VARDATA(result), \ NUM_processor(format, &Num, VARDATA(result), numstr, plen, sign, true); \
numstr, plen, sign, true); \
pfree(orgnum); \
\ \
if (shouldFree) \ if (shouldFree) \
pfree(format); \ pfree(format); \
\ \
/* /* \
* for result is allocated max memory, which current format-picture\ * Convert null-terminated representation of result to standard text. \
* needs, now it must be re-allocate to result real size \ * 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)))) \ len = strlen(VARDATA(result)); \
{ \ VARATT_SIZEP(result) = len + VARHDRSZ; \
pfree(result); \ } while (0)
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)
/* ------------------- /* -------------------
* NUMERIC to_number() (convert string to numeric) * NUMERIC to_number() (convert string to numeric)
@ -4480,7 +4466,7 @@ numeric_to_number(PG_FUNCTION_ARGS)
len = VARSIZE(fmt) - VARHDRSZ; len = VARSIZE(fmt) - VARHDRSZ;
if (len <= 0) if (len <= 0 || len >= INT_MAX/NUM_MAX_ITEM_SIZ)
PG_RETURN_NULL(); PG_RETURN_NULL();
format = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree); format = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree);
@ -4515,8 +4501,7 @@ numeric_to_char(PG_FUNCTION_ARGS)
text *fmt = PG_GETARG_TEXT_P(1); text *fmt = PG_GETARG_TEXT_P(1);
NUMDesc Num; NUMDesc Num;
FormatNode *format; FormatNode *format;
text *result, text *result;
*result_tmp;
bool shouldFree; bool shouldFree;
int len = 0, int len = 0,
plen = 0, plen = 0,
@ -4539,7 +4524,6 @@ numeric_to_char(PG_FUNCTION_ARGS)
numstr = orgnum = numstr = orgnum =
int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4, int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
NumericGetDatum(x)))); NumericGetDatum(x))));
pfree(x);
} }
else else
{ {
@ -4558,9 +4542,6 @@ numeric_to_char(PG_FUNCTION_ARGS)
val = DatumGetNumeric(DirectFunctionCall2(numeric_mul, val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
NumericGetDatum(value), NumericGetDatum(value),
NumericGetDatum(x))); NumericGetDatum(x)));
pfree(x);
pfree(a);
pfree(b);
Num.pre += Num.multi; Num.pre += Num.multi;
} }
@ -4569,10 +4550,9 @@ numeric_to_char(PG_FUNCTION_ARGS)
Int32GetDatum(Num.post))); Int32GetDatum(Num.post)));
orgnum = DatumGetCString(DirectFunctionCall1(numeric_out, orgnum = DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(x))); NumericGetDatum(x)));
pfree(x);
if (*orgnum == '-') if (*orgnum == '-')
{ /* < 0 */ {
sign = '-'; sign = '-';
numstr = orgnum + 1; numstr = orgnum + 1;
} }
@ -4590,13 +4570,10 @@ numeric_to_char(PG_FUNCTION_ARGS)
plen = Num.pre - len; plen = Num.pre - len;
else if (len > Num.pre) 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) = '.'; *(numstr + Num.pre) = '.';
fill_str(numstr + 1 + Num.pre, '#', Num.post);
} }
if (IS_MULTI(&Num))
pfree(val);
} }
NUM_TOCHAR_finish; NUM_TOCHAR_finish;
@ -4614,8 +4591,7 @@ int4_to_char(PG_FUNCTION_ARGS)
text *fmt = PG_GETARG_TEXT_P(1); text *fmt = PG_GETARG_TEXT_P(1);
NUMDesc Num; NUMDesc Num;
FormatNode *format; FormatNode *format;
text *result, text *result;
*result_tmp;
bool shouldFree; bool shouldFree;
int len = 0, int len = 0,
plen = 0, plen = 0,
@ -4643,40 +4619,34 @@ int4_to_char(PG_FUNCTION_ARGS)
orgnum = DatumGetCString(DirectFunctionCall1(int4out, orgnum = DatumGetCString(DirectFunctionCall1(int4out,
Int32GetDatum(value))); Int32GetDatum(value)));
} }
len = strlen(orgnum);
if (*orgnum == '-') if (*orgnum == '-')
{ /* < 0 */ {
sign = '-'; sign = '-';
--len; orgnum++;
} }
else else
sign = '+'; sign = '+';
len = strlen(orgnum);
if (Num.post) if (Num.post)
{ {
int i;
numstr = (char *) palloc(len + Num.post + 2); numstr = (char *) palloc(len + Num.post + 2);
strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0)); strcpy(numstr, orgnum);
*(numstr + len) = '.'; *(numstr + len) = '.';
memset(numstr + len + 1, '0', Num.post);
for (i = len + 1; i <= len + Num.post; i++)
*(numstr + i) = '0';
*(numstr + len + Num.post + 1) = '\0'; *(numstr + len + Num.post + 1) = '\0';
pfree(orgnum);
orgnum = numstr;
} }
else else
numstr = orgnum + (*orgnum == '-' ? 1 : 0); numstr = orgnum;
if (Num.pre > len) if (Num.pre > len)
plen = Num.pre - len; plen = Num.pre - len;
else if (len > Num.pre) 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) = '.'; *(numstr + Num.pre) = '.';
fill_str(numstr + 1 + Num.pre, '#', Num.post);
} }
} }
@ -4695,8 +4665,7 @@ int8_to_char(PG_FUNCTION_ARGS)
text *fmt = PG_GETARG_TEXT_P(1); text *fmt = PG_GETARG_TEXT_P(1);
NUMDesc Num; NUMDesc Num;
FormatNode *format; FormatNode *format;
text *result, text *result;
*result_tmp;
bool shouldFree; bool shouldFree;
int len = 0, int len = 0,
plen = 0, plen = 0,
@ -4730,40 +4699,34 @@ int8_to_char(PG_FUNCTION_ARGS)
orgnum = DatumGetCString(DirectFunctionCall1(int8out, orgnum = DatumGetCString(DirectFunctionCall1(int8out,
Int64GetDatum(value))); Int64GetDatum(value)));
len = strlen(orgnum);
if (*orgnum == '-') if (*orgnum == '-')
{ /* < 0 */ {
sign = '-'; sign = '-';
--len; orgnum++;
} }
else else
sign = '+'; sign = '+';
len = strlen(orgnum);
if (Num.post) if (Num.post)
{ {
int i;
numstr = (char *) palloc(len + Num.post + 2); numstr = (char *) palloc(len + Num.post + 2);
strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0)); strcpy(numstr, orgnum);
*(numstr + len) = '.'; *(numstr + len) = '.';
memset(numstr + len + 1, '0', Num.post);
for (i = len + 1; i <= len + Num.post; i++)
*(numstr + i) = '0';
*(numstr + len + Num.post + 1) = '\0'; *(numstr + len + Num.post + 1) = '\0';
pfree(orgnum);
orgnum = numstr;
} }
else else
numstr = orgnum + (*orgnum == '-' ? 1 : 0); numstr = orgnum;
if (Num.pre > len) if (Num.pre > len)
plen = Num.pre - len; plen = Num.pre - len;
else if (len > Num.pre) 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) = '.'; *(numstr + Num.pre) = '.';
fill_str(numstr + 1 + Num.pre, '#', Num.post);
} }
} }
@ -4782,8 +4745,7 @@ float4_to_char(PG_FUNCTION_ARGS)
text *fmt = PG_GETARG_TEXT_P(1); text *fmt = PG_GETARG_TEXT_P(1);
NUMDesc Num; NUMDesc Num;
FormatNode *format; FormatNode *format;
text *result, text *result;
*result_tmp;
bool shouldFree; bool shouldFree;
int len = 0, int len = 0,
plen = 0, plen = 0,
@ -4838,9 +4800,9 @@ float4_to_char(PG_FUNCTION_ARGS)
plen = Num.pre - len; plen = Num.pre - len;
else if (len > Num.pre) 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) = '.'; *(numstr + Num.pre) = '.';
fill_str(numstr + 1 + Num.pre, '#', Num.post);
} }
} }
@ -4859,8 +4821,7 @@ float8_to_char(PG_FUNCTION_ARGS)
text *fmt = PG_GETARG_TEXT_P(1); text *fmt = PG_GETARG_TEXT_P(1);
NUMDesc Num; NUMDesc Num;
FormatNode *format; FormatNode *format;
text *result, text *result;
*result_tmp;
bool shouldFree; bool shouldFree;
int len = 0, int len = 0,
plen = 0, plen = 0,
@ -4913,9 +4874,9 @@ float8_to_char(PG_FUNCTION_ARGS)
plen = Num.pre - len; plen = Num.pre - len;
else if (len > Num.pre) 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) = '.'; *(numstr + Num.pre) = '.';
fill_str(numstr + 1 + Num.pre, '#', Num.post);
} }
} }