bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Bug-gnulib] linebreak.c proposed patches for size-calculation overf


From: Paul Eggert
Subject: Re: [Bug-gnulib] linebreak.c proposed patches for size-calculation overflows
Date: 31 Oct 2003 15:38:21 -0800
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3

Bruno Haible <address@hidden> writes:

> I imagine macros that let me write:
> 
>              bool overflow = false;
>              size_t size = xsum3 (xtimes (n, sizeof (size_t), &overflow),
>                                   m,
>                                   m,
>                                   &overflow);
>              if (!overflow)
>                {
>                  char *memory = malloc (size);
> 
> What do you think?

I'd rather reserve (size_t) -1 to represent overflow, and limit myself
to binary operators, e.g.:

             char *memory = malloc (xsum (xtimes (n, sizeof (size_t)),
                                          xsum (m, m)));

but even this is relatively hard to read compared to the original, and
it assumes that malloc (SIZE_MAX) always fails, which is probably a
portable assumption but is a bit worrisome nonetheless.

> Other proposals how this code could be written in a
> maintainable way?

Currently linebreak.c doesn't include xalloc.h, but if you don't mind
depending on xalloc.h perhaps there's a macro or two that we could
add.  (For example, we could arrange for xmalloc (SIZE_MAX) to fail
reliably, if we want to use the convention that SIZE_MAX means
overflow.)

Here's another possibility, which doesn't rely on xalloc.h.  This
patch adds only 2 lines of code to linebreak.c, totalling 4 new
comparisons followed by conditional branches.  The other solutions
that I can think of offhand are all less efficient than this, which is
perhaps not that big a deal here but will be an issue elsewhere.

2003-10-31  Paul Eggert  <address@hidden>

        * linebreak.c (iconv_string_length): Return (size_t)(-1) when
        there is an size-calculation overflow.
        (mbs_possible_linebreaks, mbs_width_linebreaks):
        Do not allow overflow in size calculations.

--- linebreak.c.~1.4.~  Wed Jul 30 23:27:05 2003
+++ linebreak.c Fri Oct 31 15:15:44 2003
@@ -1379,9 +1379,10 @@ iconv_string_length (iconv_t cd, const c
       char *outptr = tmpbuf;
       size_t outsize = TMPBUFSIZE;
       size_t res = iconv (cd, (ICONV_CONST char **) &inptr, &insize, &outptr, 
&outsize);
-      if (res == (size_t)(-1) && errno != E2BIG)
+      size_t tmpcount = outptr - tmpbuf;
+      count += tmpcount;
+      if ((res == (size_t)(-1) && errno != E2BIG) || count < tmpcount)
         return (size_t)(-1);
-      count += outptr - tmpbuf;
     }
   /* Avoid glibc-2.1 bug and Solaris 7 through 9 bug.  */
 #if defined _LIBICONV_VERSION \
@@ -1390,9 +1391,10 @@ iconv_string_length (iconv_t cd, const c
     char *outptr = tmpbuf;
     size_t outsize = TMPBUFSIZE;
     size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
-    if (res == (size_t)(-1))
+    size_t tmpcount = outptr - tmpbuf;
+    count += tmpcount;
+    if (res == (size_t)(-1) || count < tmpcount)
       return (size_t)(-1);
-    count += outptr - tmpbuf;
   }
   /* Return to the initial state.  */
   iconv (cd, NULL, NULL, NULL, NULL);
@@ -1510,8 +1512,8 @@ mbs_possible_linebreaks (const char *s, 
         to_utf8 = (iconv_t)(-1);
       else
 # endif
-      to_utf8 = iconv_open (UTF8_NAME, encoding);
-      if (to_utf8 != (iconv_t)(-1))
+      if (n <= (size_t)(-1) / (sizeof (size_t) + 2 * MB_LEN_MAX)
+          && (to_utf8 = iconv_open (UTF8_NAME, encoding)) != (iconv_t)(-1))
         {
           /* Determine the length of the resulting UTF-8 string.  */
           size_t m = iconv_string_length (to_utf8, s, n);
@@ -1603,8 +1605,8 @@ mbs_width_linebreaks (const char *s, siz
         to_utf8 = (iconv_t)(-1);
       else
 # endif
-      to_utf8 = iconv_open (UTF8_NAME, encoding);
-      if (to_utf8 != (iconv_t)(-1))
+      if (n <= (size_t)(-1) / (sizeof (size_t) + 3 * MB_LEN_MAX)
+          && (to_utf8 = iconv_open (UTF8_NAME, encoding)) != (iconv_t)(-1))
         {
           /* Determine the length of the resulting UTF-8 string.  */
           size_t m = iconv_string_length (to_utf8, s, n);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]