mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-30 23:02:03 +02:00
port/snprintf(): fix overflow and do padding
Prevent port/snprintf() from overflowing its local fixed-size buffer and pad to the desired number of digits with zeros, even if the precision is beyond the ability of the native sprintf(). port/snprintf() is only used on systems that lack a native snprintf(). Reported by Bruce Momjian. Patch by Tom Lane. Backpatch to all supported versions. Security: CVE-2015-0242
This commit is contained in:
parent
9241c84cbc
commit
29725b3db6
@ -32,7 +32,9 @@
|
||||
|
||||
#include "c.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#ifndef WIN32
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
@ -932,27 +934,80 @@ fmtfloat(double value, char type, int forcesign, int leftjust,
|
||||
PrintfTarget *target)
|
||||
{
|
||||
int signvalue = 0;
|
||||
int prec;
|
||||
int vallen;
|
||||
char fmt[32];
|
||||
char convert[512];
|
||||
int padlen = 0; /* amount to pad */
|
||||
char convert[1024];
|
||||
int zeropadlen = 0; /* amount to pad with zeroes */
|
||||
int padlen = 0; /* amount to pad with spaces */
|
||||
|
||||
/*
|
||||
* We rely on the regular C library's sprintf to do the basic conversion,
|
||||
* then handle padding considerations here.
|
||||
*
|
||||
* The dynamic range of "double" is about 1E+-308 for IEEE math, and not
|
||||
* too wildly more than that with other hardware. In "f" format, sprintf
|
||||
* could therefore generate at most 308 characters to the left of the
|
||||
* decimal point; while we need to allow the precision to get as high as
|
||||
* 308+17 to ensure that we don't truncate significant digits from very
|
||||
* small values. To handle both these extremes, we use a buffer of 1024
|
||||
* bytes and limit requested precision to 350 digits; this should prevent
|
||||
* buffer overrun even with non-IEEE math. If the original precision
|
||||
* request was more than 350, separately pad with zeroes.
|
||||
*/
|
||||
if (precision < 0) /* cover possible overflow of "accum" */
|
||||
precision = 0;
|
||||
prec = Min(precision, 350);
|
||||
|
||||
/* we rely on regular C library's sprintf to do the basic conversion */
|
||||
if (pointflag)
|
||||
sprintf(fmt, "%%.%d%c", precision, type);
|
||||
{
|
||||
sprintf(fmt, "%%.%d%c", prec, type);
|
||||
zeropadlen = precision - prec;
|
||||
}
|
||||
else
|
||||
sprintf(fmt, "%%%c", type);
|
||||
|
||||
if (adjust_sign((value < 0), forcesign, &signvalue))
|
||||
if (!isnan(value) && adjust_sign((value < 0), forcesign, &signvalue))
|
||||
value = -value;
|
||||
|
||||
vallen = sprintf(convert, fmt, value);
|
||||
|
||||
adjust_padlen(minlen, vallen, leftjust, &padlen);
|
||||
/* If it's infinity or NaN, forget about doing any zero-padding */
|
||||
if (zeropadlen > 0 && !isdigit((unsigned char) convert[vallen - 1]))
|
||||
zeropadlen = 0;
|
||||
|
||||
adjust_padlen(minlen, vallen + zeropadlen, leftjust, &padlen);
|
||||
|
||||
leading_pad(zpad, &signvalue, &padlen, target);
|
||||
|
||||
dostr(convert, vallen, target);
|
||||
if (zeropadlen > 0)
|
||||
{
|
||||
/* If 'e' or 'E' format, inject zeroes before the exponent */
|
||||
char *epos = strrchr(convert, 'e');
|
||||
|
||||
if (!epos)
|
||||
epos = strrchr(convert, 'E');
|
||||
if (epos)
|
||||
{
|
||||
/* pad after exponent */
|
||||
dostr(convert, epos - convert, target);
|
||||
while (zeropadlen-- > 0)
|
||||
dopr_outch('0', target);
|
||||
dostr(epos, vallen - (epos - convert), target);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no exponent, pad after the digits */
|
||||
dostr(convert, vallen, target);
|
||||
while (zeropadlen-- > 0)
|
||||
dopr_outch('0', target);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no zero padding, just emit the number as-is */
|
||||
dostr(convert, vallen, target);
|
||||
}
|
||||
|
||||
trailing_pad(&padlen, target);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user