X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Fvasnprintf.c;h=3b496d2539d44f606cf4af569e3b1366b51dc759;hb=0cba35775b73cee99107fba2be2bf62036ad6c0c;hp=380170deef91bdb15ace9894f17134242e127c8f;hpb=a416aa560a13c4fc49a39ab5f0225c999bcda510;p=gnulib.git diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index 380170dee..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,13 +51,9 @@ /* Checked size_t computations. */ #include "xsize.h" -/* For those losing systems which don't have 'alloca' we have to add - some additional code emulating it. */ -#ifdef HAVE_ALLOCA -# define freea(p) /* nothing */ -#else -# define alloca(n) malloc (n) -# define freea(p) free (p) +/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */ +#ifndef EOVERFLOW +# define EOVERFLOW E2BIG #endif #ifdef HAVE_WCHAR_T @@ -139,10 +135,9 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } { - size_t buf_neededlength = - xsum4 (7, d.max_width_length, d.max_precision_length, 6); - CHAR_T *buf = - (CHAR_T *) alloca (xtimes (buf_neededlength, sizeof (CHAR_T))); + size_t buf_neededlength; + CHAR_T *buf; + CHAR_T *buf_malloced; const CHAR_T *cp; size_t i; DIRECTIVE *dp; @@ -151,6 +146,28 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar size_t allocated; size_t length; + /* Allocate a small buffer that will hold a directive passed to + sprintf or snprintf. */ + buf_neededlength = + xsum4 (7, d.max_width_length, d.max_precision_length, 6); +#if HAVE_ALLOCA + if (buf_neededlength < 4000 / sizeof (CHAR_T)) + { + buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T)); + buf_malloced = NULL; + } + else +#endif + { + size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T)); + if (size_overflow_p (buf_memsize)) + goto out_of_memory_1; + buf = (CHAR_T *) malloc (buf_memsize); + if (buf == NULL) + goto out_of_memory_1; + buf_malloced = buf; + } + if (resultbuf != NULL) { result = resultbuf; @@ -210,7 +227,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { size_t augmented_length; - if (!(dp->arg_index < 0)) + if (!(dp->arg_index == ARG_NONE)) abort (); augmented_length = xsum (length, 1); ENSURE_ALLOCATION (augmented_length); @@ -219,7 +236,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar } else { - if (!(dp->arg_index >= 0)) + if (!(dp->arg_index != ARG_NONE)) abort (); if (dp->conversion == 'n') @@ -267,7 +284,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar width = 0; if (dp->width_start != dp->width_end) { - if (dp->width_arg_index >= 0) + if (dp->width_arg_index != ARG_NONE) { int arg; @@ -289,7 +306,7 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar precision = 6; if (dp->precision_start != dp->precision_end) { - if (dp->precision_arg_index >= 0) + if (dp->precision_arg_index != ARG_NONE) { int arg; @@ -303,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); } } @@ -318,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': @@ -349,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) @@ -358,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': @@ -376,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) @@ -385,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': @@ -551,13 +569,13 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar /* Construct the arguments for calling snprintf or sprintf. */ prefix_count = 0; - if (dp->width_arg_index >= 0) + if (dp->width_arg_index != ARG_NONE) { if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) abort (); prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int; } - if (dp->precision_arg_index >= 0) + if (dp->precision_arg_index != ARG_NONE) { if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) abort (); @@ -788,7 +806,8 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar { if (!(result == resultbuf || result == NULL)) free (result); - freea (buf); + if (buf_malloced != NULL) + free (buf_malloced); CLEANUP (); errno = EINVAL; return NULL; @@ -846,15 +865,29 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar result = memory; } - freea (buf); + if (buf_malloced != NULL) + 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); - freea (buf); + if (buf_malloced != NULL) + free (buf_malloced); + out_of_memory_1: CLEANUP (); errno = ENOMEM; return NULL;