Fix computation of newsize during reallocation.
authorBruno Haible <bruno@clisp.org>
Thu, 1 May 2008 14:49:21 +0000 (16:49 +0200)
committerBruno Haible <bruno@clisp.org>
Thu, 1 May 2008 14:49:21 +0000 (16:49 +0200)
ChangeLog
lib/getndelim2.c

index 03e2df7..f3b5bf9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2008-05-01  Bruno Haible  <bruno@clisp.org>
+
+       * lib/getndelim2.c (getndelim2): Fix newsize computation during
+       reallocation. Rename 'done' to 'found_delimiter'.
+
 2008-05-01  Jim Meyering  <meyering@redhat.com>
 
        vc-list-files: accommodate /bin/sh like the one from Solaris 10
index 04349ad..9dcb9fe 100644 (file)
@@ -76,7 +76,7 @@ getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
   ssize_t bytes_stored = -1;
   char *ptr = *lineptr;
   size_t size = *linesize;
-  bool done = false;
+  bool found_delimiter;
 
   if (!ptr)
     {
@@ -103,7 +103,8 @@ getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
 
   flockfile (stream);
 
-  while (!done)
+  found_delimiter = false;
+  do
     {
       /* Here always ptr + size == read_pos + nbytes_avail.
         Also nbytes_avail > 0 || size < nmax.  */
@@ -121,7 +122,7 @@ getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
              if (end)
                {
                  buffer_len = end - buffer + 1;
-                 done = true;
+                 found_delimiter = true;
                }
            }
        }
@@ -137,7 +138,7 @@ getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
                break;
            }
          if (c == delim1 || c == delim2)
-           done = true;
+           found_delimiter = true;
          buffer_len = 1;
        }
 
@@ -145,13 +146,18 @@ getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
         always (unless we get an error while reading the first byte)
         NUL-terminate the line buffer.  */
 
-      if (nbytes_avail < 1 + buffer_len && size < nmax)
+      if (nbytes_avail < buffer_len + 1 && size < nmax)
        {
+         /* Grow size proportionally, not linearly, to avoid O(n^2)
+            running time.  */
          size_t newsize = size < MIN_CHUNK ? size + MIN_CHUNK : 2 * size;
          char *newptr;
 
-         if (newsize < buffer_len)
-           newsize = buffer_len + size;
+         /* Increase newsize so that it becomes
+            >= (read_pos - ptr) + buffer_len.  */
+         if (newsize - (read_pos - ptr) < buffer_len + 1)
+           newsize = (read_pos - ptr) + buffer_len + 1;
+         /* Respect nmax.  This handles possible integer overflow.  */
          if (! (size < newsize && newsize <= nmax))
            newsize = nmax;
 
@@ -193,6 +199,7 @@ getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
       if (buffer && freadseek (stream, buffer_len))
        goto unlock_done;
     }
+  while (!found_delimiter);
 
   /* Done - NUL terminate and return the number of bytes read.
      At this point we know that nbytes_avail >= 1.  */