+2003-11-17 Bruno Haible <bruno@clisp.org>
+
+ * modules/vasnprintf (Files): Add m4/ssize_t.m4.
+ (Depends-on): Add xsize.
+
2003-11-12 Paul Eggert <eggert@twinsun.com>
* modules/xalloc (Files): Undo latest change, since xalloc.h
+2003-11-16 Paul Eggert <eggert@twinsun.com>
+ Bruno Haible <bruno@clisp.org>
+
+ Protect against address arithmetic overflow.
+ * printf-args.h: Include stddef.h.
+ (arguments): Change type of field 'count' to size_t.
+ * printf-args.c (printf_fetchargs): Use size_t instead of
+ 'unsigned int' where appropriate.
+ * printf-parse.h: Include sys/types.h.
+ (char_directive): Change type of *arg_index fields to ssize_t.
+ (char_directives): Change type of fields 'count', max_*_length to
+ size_t.
+ * printf-parse.c: Include sys/types.h and xsize.h.
+ (SSIZE_MAX): Define fallback value.
+ (PRINTF_PARSE): Use size_t instead of 'unsigned int' and ssize_t
+ instead of 'int' where appropriate. Check a_allocated, d_allocated
+ against overflow. Reject %m$ argument numbers > SSIZE_MAX + 1.
+ * vasnprintf.c: Include xsize.h.
+ (VASNPRINTF): Use size_t instead of 'unsigned int' where appropriate.
+ Check alloca, malloc, realloc, ENSURE_ALLOCATION arguments against
+ overflow. Avoid wraparound when converting a width or precision from
+ decimal to binary.
+
+2003-11-16 Bruno Haible <bruno@clisp.org>
+
+ Update from GNU gettext.
+ * printf-parse.c: Generalize to it can be compiled for wide strings.
+ (PRINTF_PARSE, CHAR_T, DIRECTIVE, DIRECTIVES): New macros.
+ * vasnprintf.c: Generalize to it can be compiled for wide strings.
+ (VASNPRINTF, CHAR_T, DIRECTIVE, DIRECTIVES, PRINTF_PARSE, USE_SNPRINTF,
+ SNPRINTF): New macros.
+ Don't include <alloca.h> if the file is used inside libintl.
+ (local_wcslen): New function, for Solaris 2.5.1.
+ (VASNPRINTF): Use it instead of wcslen.
+
2003-11-16 Bruno Haible <bruno@clisp.org>
* xsize.h (xmax): New function.
int
printf_fetchargs (va_list args, arguments *a)
{
- unsigned int i;
+ size_t i;
argument *ap;
for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++)
#ifndef _PRINTF_ARGS_H
#define _PRINTF_ARGS_H
+/* Get size_t. */
+#include <stddef.h>
+
/* Get wchar_t. */
#ifdef HAVE_WCHAR_T
# include <stddef.h>
typedef struct
{
- unsigned int count;
+ size_t count;
argument *arg;
}
arguments;
/* Get size_t, NULL. */
#include <stddef.h>
+/* Get ssize_t. */
+#include <sys/types.h>
+
/* Get intmax_t. */
#if HAVE_STDINT_H_WITH_UINTMAX
# include <stdint.h>
/* malloc(), realloc(), free(). */
#include <stdlib.h>
+/* Checked size_t computations. */
+#include "xsize.h"
+
+#ifndef SSIZE_MAX
+# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
+#endif
+
#if WIDE_CHAR_VERSION
# define PRINTF_PARSE wprintf_parse
# define CHAR_T wchar_t
PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
{
const CHAR_T *cp = format; /* pointer into format */
- int arg_posn = 0; /* number of regular arguments consumed */
- unsigned int d_allocated; /* allocated elements of d->dir */
- unsigned int a_allocated; /* allocated elements of a->arg */
- unsigned int max_width_length = 0;
- unsigned int max_precision_length = 0;
+ ssize_t arg_posn = 0; /* number of regular arguments consumed */
+ size_t d_allocated; /* allocated elements of d->dir */
+ size_t a_allocated; /* allocated elements of a->arg */
+ size_t max_width_length = 0;
+ size_t max_precision_length = 0;
d->count = 0;
d_allocated = 1;
#define REGISTER_ARG(_index_,_type_) \
{ \
- unsigned int n = (_index_); \
+ size_t n = (_index_); \
if (n >= a_allocated) \
{ \
+ size_t memory_size; \
argument *memory; \
- a_allocated = 2 * a_allocated; \
+ \
+ a_allocated = xtimes (a_allocated, 2); \
if (a_allocated <= n) \
- a_allocated = n + 1; \
+ a_allocated = xsum (n, 1); \
+ memory_size = xtimes (a_allocated, sizeof (argument)); \
+ if (size_overflow_p (memory_size)) \
+ /* Overflow, would lead to out of memory. */ \
+ goto error; \
memory = (a->arg \
- ? realloc (a->arg, a_allocated * sizeof (argument)) \
- : malloc (a_allocated * sizeof (argument))); \
+ ? realloc (a->arg, memory_size) \
+ : malloc (memory_size)); \
if (memory == NULL) \
/* Out of memory. */ \
goto error; \
CHAR_T c = *cp++;
if (c == '%')
{
- int arg_index = -1;
+ ssize_t arg_index = -1;
DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
/* Initialize the next directive. */
;
if (*np == '$')
{
- unsigned int n = 0;
+ size_t n = 0;
for (np = cp; *np >= '0' && *np <= '9'; np++)
- n = 10 * n + (*np - '0');
+ n = xsum (xtimes (n, 10), *np - '0');
if (n == 0)
/* Positional argument 0. */
goto error;
+ if (size_overflow_p (n) || n - 1 > SSIZE_MAX)
+ /* n too large, would lead to out of memory later. */
+ goto error;
arg_index = n - 1;
cp = np + 1;
}
;
if (*np == '$')
{
- unsigned int n = 0;
+ size_t n = 0;
for (np = cp; *np >= '0' && *np <= '9'; np++)
- n = 10 * n + (*np - '0');
+ n = xsum (xtimes (n, 10), *np - '0');
if (n == 0)
/* Positional argument 0. */
goto error;
+ if (size_overflow_p (n) || n - 1 > SSIZE_MAX)
+ /* n too large, would lead to out of memory later. */
+ goto error;
dp->width_arg_index = n - 1;
cp = np + 1;
}
}
if (dp->width_arg_index < 0)
- dp->width_arg_index = arg_posn++;
+ {
+ dp->width_arg_index = arg_posn++;
+ if (dp->width_arg_index < 0)
+ /* arg_posn wrapped around at SSIZE_MAX. */
+ goto error;
+ }
REGISTER_ARG (dp->width_arg_index, TYPE_INT);
}
else if (*cp >= '0' && *cp <= '9')
{
- unsigned int width_length;
+ size_t width_length;
dp->width_start = cp;
for (; *cp >= '0' && *cp <= '9'; cp++)
;
if (*np == '$')
{
- unsigned int n = 0;
+ size_t n = 0;
for (np = cp; *np >= '0' && *np <= '9'; np++)
- n = 10 * n + (*np - '0');
+ n = xsum (xtimes (n, 10), *np - '0');
if (n == 0)
/* Positional argument 0. */
goto error;
+ if (size_overflow_p (n) || n - 1 > SSIZE_MAX)
+ /* n too large, would lead to out of memory
+ later. */
+ goto error;
dp->precision_arg_index = n - 1;
cp = np + 1;
}
}
if (dp->precision_arg_index < 0)
- dp->precision_arg_index = arg_posn++;
+ {
+ dp->precision_arg_index = arg_posn++;
+ if (dp->precision_arg_index < 0)
+ /* arg_posn wrapped around at SSIZE_MAX. */
+ goto error;
+ }
REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
}
else
{
- unsigned int precision_length;
+ size_t precision_length;
dp->precision_start = cp - 1;
for (; *cp >= '0' && *cp <= '9'; cp++)
{
dp->arg_index = arg_index;
if (dp->arg_index < 0)
- dp->arg_index = arg_posn++;
+ {
+ dp->arg_index = arg_posn++;
+ if (dp->arg_index < 0)
+ /* arg_posn wrapped around at SSIZE_MAX. */
+ goto error;
+ }
REGISTER_ARG (dp->arg_index, type);
}
dp->conversion = c;
d->count++;
if (d->count >= d_allocated)
{
+ size_t memory_size;
DIRECTIVE *memory;
- d_allocated = 2 * d_allocated;
- memory = realloc (d->dir, d_allocated * sizeof (DIRECTIVE));
+ d_allocated = xtimes (d_allocated, 2);
+ if (size_overflow_p (d_allocated))
+ /* Overflow, would lead to out of memory. */
+ goto error;
+ memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
+ if (size_overflow_p (memory_size))
+ /* Overflow, would lead to out of memory. */
+ goto error;
+ memory = realloc (d->dir, memory_size);
if (memory == NULL)
/* Out of memory. */
goto error;
/* Parse printf format string.
- Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002-2003 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
#include "printf-args.h"
+/* Get ssize_t. */
+#include <sys/types.h>
+
/* Flags */
#define FLAG_GROUP 1 /* ' flag */
int flags;
const char* width_start;
const char* width_end;
- int width_arg_index;
+ ssize_t width_arg_index;
const char* precision_start;
const char* precision_end;
- int precision_arg_index;
+ ssize_t precision_arg_index;
char conversion; /* d i o u x X f e E g G c s p n U % but not C S */
- int arg_index;
+ ssize_t arg_index;
}
char_directive;
/* A parsed format string. */
typedef struct
{
- unsigned int count;
+ size_t count;
char_directive *dir;
- unsigned int max_width_length;
- unsigned int max_precision_length;
+ size_t max_width_length;
+ size_t max_precision_length;
}
char_directives;
# include "printf-parse.h"
#endif
+/* 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
}
{
+ size_t buf_neededlength =
+ xsum4 (7, d.max_width_length, d.max_precision_length, 6);
CHAR_T *buf =
- (CHAR_T *) alloca ((7 + d.max_width_length + d.max_precision_length + 6)
- * sizeof (CHAR_T));
+ (CHAR_T *) alloca (xtimes (buf_neededlength, sizeof (CHAR_T)));
const CHAR_T *cp;
- unsigned int i;
+ size_t i;
DIRECTIVE *dp;
/* Output string accumulator. */
CHAR_T *result;
result is either == resultbuf or == NULL or malloc-allocated.
If length > 0, then result != NULL. */
+ /* Ensures that allocated >= needed. Aborts through a jump to
+ out_of_memory if needed is SIZE_MAX or otherwise too big. */
#define ENSURE_ALLOCATION(needed) \
if ((needed) > allocated) \
{ \
+ size_t memory_size; \
CHAR_T *memory; \
\
- allocated = (allocated > 0 ? 2 * allocated : 12); \
+ allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \
if ((needed) > allocated) \
allocated = (needed); \
+ memory_size = xtimes (allocated, sizeof (CHAR_T)); \
+ if (size_overflow_p (memory_size)) \
+ goto out_of_memory; \
if (result == resultbuf || result == NULL) \
- memory = (CHAR_T *) malloc (allocated * sizeof (CHAR_T)); \
+ memory = (CHAR_T *) malloc (memory_size); \
else \
- memory = (CHAR_T *) realloc (result, allocated * sizeof (CHAR_T)); \
- \
+ memory = (CHAR_T *) realloc (result, memory_size); \
if (memory == NULL) \
- { \
- if (!(result == resultbuf || result == NULL)) \
- free (result); \
- freea (buf); \
- CLEANUP (); \
- errno = ENOMEM; \
- return NULL; \
- } \
+ goto out_of_memory; \
if (result == resultbuf && length > 0) \
memcpy (memory, result, length * sizeof (CHAR_T)); \
result = memory; \
if (cp != dp->dir_start)
{
size_t n = dp->dir_start - cp;
+ size_t augmented_length = xsum (length, n);
- ENSURE_ALLOCATION (length + n);
+ ENSURE_ALLOCATION (augmented_length);
memcpy (result + length, cp, n * sizeof (CHAR_T));
- length += n;
+ length = augmented_length;
}
if (i == d.count)
break;
/* Execute a single directive. */
if (dp->conversion == '%')
{
+ size_t augmented_length;
+
if (!(dp->arg_index < 0))
abort ();
- ENSURE_ALLOCATION (length + 1);
+ augmented_length = xsum (length, 1);
+ ENSURE_ALLOCATION (augmented_length);
result[length] = '%';
- length += 1;
+ length = augmented_length;
}
else
{
unsigned int prefix_count;
int prefixes[2];
#if !USE_SNPRINTF
- unsigned int tmp_length;
+ size_t tmp_length;
CHAR_T tmpbuf[700];
CHAR_T *tmp;
/* Allocate a temporary buffer of sufficient size for calling
sprintf. */
{
- unsigned int width;
- unsigned int precision;
+ size_t width;
+ size_t precision;
width = 0;
if (dp->width_start != dp->width_end)
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
- width = (arg < 0 ? -arg : arg);
+ width = (arg < 0 ? (unsigned int) (-arg) : arg);
}
else
{
const CHAR_T *digitp = dp->width_start;
do
- width = width * 10 + (*digitp++ - '0');
+ width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
}
precision = 0;
do
- precision = precision * 10 + (*digitp++ - '0');
+ precision = xsum (xtimes (precision, 10), *digitp++ - '0');
while (digitp != dp->precision_end);
}
}
* 2 /* estimate for FLAG_GROUP */
)
+ 1 /* turn floor into ceil */
- + precision
+ 10; /* sign, decimal point etc. */
else
# endif
* 2 /* estimate for FLAG_GROUP */
)
+ 1 /* turn floor into ceil */
- + precision
+ 10; /* sign, decimal point etc. */
+ tmp_length = xsum (tmp_length, precision);
break;
case 'e': case 'E': case 'g': case 'G':
case 'a': case 'A':
tmp_length =
- precision
- + 12; /* sign, decimal point, exponent etc. */
+ 12; /* sign, decimal point, exponent etc. */
+ tmp_length = xsum (tmp_length, precision);
break;
case 'c':
case 's':
# ifdef HAVE_WCHAR_T
if (type == TYPE_WIDE_STRING)
-# if WIDE_CHAR_VERSION
- tmp_length =
- local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
-# else
- tmp_length =
- local_wcslen (a.arg[dp->arg_index].a.a_wide_string)
- * MB_CUR_MAX;
+ {
+ tmp_length =
+ local_wcslen (a.arg[dp->arg_index].a.a_wide_string);
+
+# if !WIDE_CHAR_VERSION
+ tmp_length = xtimes (tmp_length, MB_CUR_MAX);
# endif
+ }
else
# endif
tmp_length = strlen (a.arg[dp->arg_index].a.a_string);
if (tmp_length < width)
tmp_length = width;
- tmp_length++; /* account for trailing NUL */
+ tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
}
if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T))
tmp = tmpbuf;
else
{
- tmp = (CHAR_T *) malloc (tmp_length * sizeof (CHAR_T));
+ size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T));
+
+ if (size_overflow_p (tmp_memsize))
+ /* Overflow, would lead to out of memory. */
+ goto out_of_memory;
+ tmp = (CHAR_T *) malloc (tmp_memsize);
if (tmp == NULL)
- {
- /* Out of memory. */
- if (!(result == resultbuf || result == NULL))
- free (result);
- freea (buf);
- CLEANUP ();
- errno = ENOMEM;
- return NULL;
- }
+ /* Out of memory. */
+ goto out_of_memory;
}
#endif
#if USE_SNPRINTF
/* Prepare checking whether snprintf returns the count
via %n. */
- ENSURE_ALLOCATION (length + 1);
+ ENSURE_ALLOCATION (xsum (length, 1));
result[length] = '\0';
#endif
*and* it returns -1 (rather than the length
that would have been required) when the
buffer is too small. */
- size_t bigger_need = 2 * allocated + 12;
+ size_t bigger_need =
+ xsum (xtimes (allocated, 2), 12);
ENSURE_ALLOCATION (bigger_need);
continue;
}
/* Need at least count bytes. But allocate
proportionally, to avoid looping eternally if
snprintf() reports a too small count. */
- size_t n = length + count;
-
- if (n < 2 * allocated)
- n = 2 * allocated;
+ size_t n =
+ xmax (xsum (length, count), xtimes (allocated, 2));
ENSURE_ALLOCATION (n);
#if USE_SNPRINTF
}
/* Add the final NUL. */
- ENSURE_ALLOCATION (length + 1);
+ ENSURE_ALLOCATION (xsum (length, 1));
result[length] = '\0';
if (result != resultbuf && length + 1 < allocated)
CLEANUP ();
*lengthp = length;
return result;
+
+ out_of_memory:
+ if (!(result == resultbuf || result == NULL))
+ free (result);
+ freea (buf);
+ CLEANUP ();
+ errno = ENOMEM;
+ return NULL;
}
}
+2003-11-17 Bruno Haible <bruno@clisp.org>
+
+ * vasnprintf.m4 (gl_PREREQ_PRINTF_PARSE): Require gt_TYPE_SSIZE_T.
+
2003-11-12 Paul Eggert <eggert@twinsun.com>
* xalloc.m4 (gl_PREREQ_XALLOC): Do not require gl_SIZE_MAX or
* size_max.m4: New file.
* ptrdiff_max.m4: New file.
* xsize,m4 (gl_XSIZE): Require gl_SIZE_MAX.
- * xalloc.m4 (gl_PREREQ_XALLOC): New file.
+ * xalloc.m4 (gl_PREREQ_XALLOC): New macro.
(gl_XALLOC): Invoke it.
2003-11-04 Bruno Haible <bruno@clisp.org>
-# vasnprintf.m4 serial 2
+# vasnprintf.m4 serial 3
dnl Copyright (C) 2002-2003 Free Software Foundation, Inc.
dnl This file is free software, distributed under the terms of the GNU
dnl General Public License. As a special exception to the GNU General
AC_REQUIRE([gt_TYPE_WCHAR_T])
AC_REQUIRE([gt_TYPE_WINT_T])
AC_REQUIRE([AC_TYPE_SIZE_T])
+ AC_REQUIRE([gt_TYPE_SSIZE_T])
AC_CHECK_TYPES(ptrdiff_t)
AC_REQUIRE([gt_AC_TYPE_INTMAX_T])
])
m4/wint_t.m4
m4/longlong.m4
m4/intmax_t.m4
+m4/ssize_t.m4
m4/vasnprintf.m4
Depends-on:
alloca
+xsize
configure.ac:
gl_FUNC_VASNPRINTF