# HG changeset patch # User Bruno Haible # Date 1299934483 -3600 # Node ID 07a5551df5ac9d844d1141a1280a3b33d70bb7a7 # Parent c4c3d3ee58b19707df22b6fbcd865ee9937edc10 wcswidth, mbswidth: Avoid integer overflow. * lib/wcswidth.c: Include . * lib/wcswidth-impl.h (wcswidth): Avoid 'int' overflow. * lib/mbswidth.c: Include . (mbsnwidth): Avoid 'int' overflow. Reported by Jim Meyering. diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2011-03-12 Bruno Haible + + wcswidth, mbswidth: Avoid integer overflow. + * lib/wcswidth.c: Include . + * lib/wcswidth-impl.h (wcswidth): Avoid 'int' overflow. + * lib/mbswidth.c: Include . + (mbsnwidth): Avoid 'int' overflow. + Reported by Jim Meyering. + 2011-03-12 Bruno Haible futimens, utimensat: Avoid endless recursion on Solaris 10. diff --git a/lib/mbswidth.c b/lib/mbswidth.c --- a/lib/mbswidth.c +++ b/lib/mbswidth.c @@ -35,12 +35,14 @@ /* Get iswcntrl(). */ #include +/* Get INT_MAX. */ +#include + /* Returns the number of columns needed to represent the multibyte character string pointed to by STRING. If a non-printable character occurs, and MBSW_REJECT_UNPRINTABLE is specified, -1 is returned. With flags = MBSW_REJECT_INVALID | MBSW_REJECT_UNPRINTABLE, this is - the multibyte analogue of the wcswidth function. - If STRING is not of length < INT_MAX / 2, integer overflow can occur. */ + the multibyte analogue of the wcswidth function. */ int mbswidth (const char *string, int flags) { @@ -50,8 +52,7 @@ /* Returns the number of columns needed to represent the multibyte character string pointed to by STRING of length NBYTES. If a non-printable character occurs, and MBSW_REJECT_UNPRINTABLE is - specified, -1 is returned. - If NBYTES is not < INT_MAX / 2, integer overflow can occur. */ + specified, -1 is returned. */ int mbsnwidth (const char *string, size_t nbytes, int flags) { @@ -135,11 +136,22 @@ w = wcwidth (wc); if (w >= 0) /* A printable multibyte character. */ - width += w; + { + if (w > INT_MAX - width) + goto overflow; + width += w; + } else /* An unprintable multibyte character. */ if (!(flags & MBSW_REJECT_UNPRINTABLE)) - width += (iswcntrl (wc) ? 0 : 1); + { + if (!iswcntrl (wc)) + { + if (width == INT_MAX) + goto overflow; + width++; + } + } else return -1; @@ -157,11 +169,25 @@ unsigned char c = (unsigned char) *p++; if (isprint (c)) - width++; + { + if (width == INT_MAX) + goto overflow; + width++; + } else if (!(flags & MBSW_REJECT_UNPRINTABLE)) - width += (iscntrl (c) ? 0 : 1); + { + if (!iscntrl (c)) + { + if (width == INT_MAX) + goto overflow; + width++; + } + } else return -1; } return width; + + overflow: + return INT_MAX; } diff --git a/lib/wcswidth-impl.h b/lib/wcswidth-impl.h --- a/lib/wcswidth-impl.h +++ b/lib/wcswidth-impl.h @@ -28,6 +28,8 @@ int width = wcwidth (c); if (width < 0) goto found_nonprinting; + if (width > INT_MAX - count) + goto overflow; count += width; } } @@ -35,4 +37,7 @@ found_nonprinting: return -1; + + overflow: + return INT_MAX; } diff --git a/lib/wcswidth.c b/lib/wcswidth.c --- a/lib/wcswidth.c +++ b/lib/wcswidth.c @@ -20,4 +20,6 @@ /* Specification. */ #include +#include + #include "wcswidth-impl.h"