X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fvasnprintf.c;h=3b496d2539d44f606cf4af569e3b1366b51dc759;hb=da326536990b4518c6e067ef773321d2e3d20889;hp=c0754ead9a3ecee7668ef3180f5e8dd743a3dc22;hpb=4831ead44de7705efcffc76f5234fab59a7b1d9e;p=gnulib.git diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index c0754ead9..3b496d253 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -1,5 +1,5 @@ /* vsprintf with automatic memory allocation. - Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002-2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Tell glibc's to provide a prototype for snprintf(). This must come before because may include @@ -40,7 +40,7 @@ #include /* abort(), malloc(), realloc(), free() */ #include /* memcpy(), strlen() */ #include /* errno */ -#include /* CHAR_BIT */ +#include /* CHAR_BIT, INT_MAX */ #include /* DBL_MAX_EXP, LDBL_MAX_EXP */ #if WIDE_CHAR_VERSION # include "wprintf-parse.h" @@ -51,6 +51,11 @@ /* Checked size_t computations. */ #include "xsize.h" +/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */ +#ifndef EOVERFLOW +# define EOVERFLOW E2BIG +#endif + #ifdef HAVE_WCHAR_T # ifdef HAVE_WCSLEN # define local_wcslen wcslen @@ -315,9 +320,8 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar const CHAR_T *digitp = dp->precision_start + 1; precision = 0; - do + while (digitp != dp->precision_end) precision = xsum (xtimes (precision, 10), *digitp++ - '0'); - while (digitp != dp->precision_end); } } @@ -330,28 +334,28 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.30103 /* binary -> decimal */ - * 2 /* estimate for FLAG_GROUP */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ else # endif if (type == TYPE_LONGINT || type == TYPE_ULONGINT) tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.30103 /* binary -> decimal */ - * 2 /* estimate for FLAG_GROUP */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ else tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.30103 /* binary -> decimal */ - * 2 /* estimate for FLAG_GROUP */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ + if (tmp_length < precision) + tmp_length = precision; + /* Multiply by 2, as an estimate for FLAG_GROUP. */ + tmp_length = xsum (tmp_length, tmp_length); + /* Add 1, to account for a leading sign. */ + tmp_length = xsum (tmp_length, 1); break; case 'o': @@ -361,8 +365,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.333334 /* binary -> octal */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ else # endif if (type == TYPE_LONGINT || type == TYPE_ULONGINT) @@ -370,15 +373,17 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.333334 /* binary -> octal */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ else tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.333334 /* binary -> octal */ ) - + 1 /* turn floor into ceil */ - + 1; /* account for leading sign */ + + 1; /* turn floor into ceil */ + if (tmp_length < precision) + tmp_length = precision; + /* Add 1, to account for a leading sign. */ + tmp_length = xsum (tmp_length, 1); break; case 'x': case 'X': @@ -388,8 +393,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ ) - + 1 /* turn floor into ceil */ - + 2; /* account for leading sign or alternate form */ + + 1; /* turn floor into ceil */ else # endif if (type == TYPE_LONGINT || type == TYPE_ULONGINT) @@ -397,15 +401,17 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ ) - + 1 /* turn floor into ceil */ - + 2; /* account for leading sign or alternate form */ + + 1; /* turn floor into ceil */ else tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ ) - + 1 /* turn floor into ceil */ - + 2; /* account for leading sign or alternate form */ + + 1; /* turn floor into ceil */ + if (tmp_length < precision) + tmp_length = precision; + /* Add 2, to account for a leading sign or alternate form. */ + tmp_length = xsum (tmp_length, 2); break; case 'f': case 'F': @@ -863,8 +869,19 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar free (buf_malloced); CLEANUP (); *lengthp = length; + if (length > INT_MAX) + goto length_overflow; return result; + length_overflow: + /* We could produce such a big string, but its length doesn't fit into + an 'int'. POSIX says that snprintf() fails with errno = EOVERFLOW in + this case. */ + if (result != resultbuf) + free (result); + errno = EOVERFLOW; + return NULL; + out_of_memory: if (!(result == resultbuf || result == NULL)) free (result);