vfprintf typing problem
Carlos O'Donell
carlos@systemhalted.org
Fri Mar 30 12:55:00 GMT 2012
On Fri, Mar 30, 2012 at 4:18 AM, David Miller <davem@davemloft.net> wrote:
> I propose the following patch.
>
> At the points where the "(size_t) -1 / sizeof(CHAT_T)" checks exist
> the 'width' has been "normalized" to be positive. If it was negative,
> that state has been recorded in the 'left' variable.
>
> So we can just directly sanity check whether width (plus the 32-bytes
> of slack) is >= INT_MAX.
>
> Therefore we have two levels of protection in this code:
>
> 1) Individual field widths are validated against INT_MAX
>
> 2) The total result (stored in 'done') is validated against
> overflowing INT_MAX as it accumulates, via the done_add() macro.
>
> I've also adjusted bug22.c so that it tests both of those cases.
>
> 2012-03-30 David S. Miller <davem@davemloft.net>
>
> * stdio-common/vfprintf.c (vfprintf): Validate width against
> overflow of INT_MAX. Set errno to EOVERFLOW when 'done' overflows
> INT_MAX.
> * stdio-common/bug22.c: Adjust to test both width INT_MAX overflow
> as well as total length INT_MAX overflow. Check explicitly for
> proper errno values.
>
> diff --git a/stdio-common/bug22.c b/stdio-common/bug22.c
> index 2228388..6b6bb43 100644
> --- a/stdio-common/bug22.c
> +++ b/stdio-common/bug22.c
> @@ -1,12 +1,18 @@
> /* BZ #5424 */
> #include <stdio.h>
> +#include <errno.h>
>
> +/* INT_MAX + 1 */
> #define N 2147483648
>
> +/* (INT_MAX / 2) + 2 */
> +#define N2 1073741825
> +
> #define STRINGIFY(S) #S
> #define MAKE_STR(S) STRINGIFY(S)
>
> #define SN MAKE_STR(N)
> +#define SN2 MAKE_STR(N2)
>
> static int
> do_test (void)
> @@ -20,11 +26,15 @@ do_test (void)
> return 1;
> }
>
> - ret = fprintf (fp, "%" SN "d%" SN "d", 1, 1);
> + ret = fprintf (fp, "%" SN "d", 1);
> + printf ("ret = %d\n", ret);
> + if (ret != -1 || errno != ERANGE)
> + return 1;
>
> + ret = fprintf (fp, "%" SN2 "d%" SN2 "d", 1, 1);
> printf ("ret = %d\n", ret);
>
> - return ret != -1;
> + return ret != -1 || errno != EOVERFLOW;
> }
>
> #define TIMEOUT 30
> diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
> index 1e90483..4875fe0 100644
> --- a/stdio-common/vfprintf.c
> +++ b/stdio-common/vfprintf.c
> @@ -71,6 +71,7 @@
> < _val, 0)) \
> { \
> done = -1; \
> + __set_errno (EOVERFLOW); \
> goto all_done; \
> } \
> done += _val; \
> @@ -141,12 +142,18 @@
> do \
> { \
> assert ((size_t) done <= (size_t) INT_MAX); \
> - if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len) \
> - || (size_t) INT_MAX - (size_t) done < (size_t) (Len)) \
> + if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)) \
> { \
> done = -1; \
> goto all_done; \
> } \
> + if (__builtin_expect ((unsigned int) INT_MAX - (unsigned int) done \
> + < (Len), 0)) \
> + { \
> + done = -1; \
> + __set_errno (EOVERFLOW); \
> + goto all_done; \
> + } \
> done += (Len); \
> } \
> while (0)
> @@ -1449,7 +1456,8 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
> left = 1;
> }
>
> - if (__builtin_expect (width >= (size_t) -1 / sizeof (CHAR_T) - 32, 0))
> + if (__builtin_expect ((unsigned int) width >= INT_MAX
> + / sizeof (CHAR_T) - 32, 0))
> {
> __set_errno (ERANGE);
> done = -1;
> @@ -1481,7 +1489,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
> LABEL (width):
> width = read_int (&f);
>
> - if (__builtin_expect (width >= (size_t) -1 / sizeof (CHAR_T) - 32, 0))
> + if (__builtin_expect ((unsigned int) width >= INT_MAX / sizeof (CHAR_T) - 32, 0))
> {
> __set_errno (ERANGE);
> done = -1;
Thanks for slogging through this, the patch is looking good so far.
Could you explain why we don't also need to fix the same problem with `prec'?
Cheers,
Carlos.
More information about the Libc-alpha
mailing list