changeset 10028:bd5f3690f627

Fix computation of newsize during reallocation.
author Bruno Haible <bruno@clisp.org>
date Thu, 01 May 2008 16:49:21 +0200
parents 8849272e39e8
children 8f3d95672dd7
files ChangeLog lib/getndelim2.c
diffstat 2 files changed, 19 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- 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
--- a/lib/getndelim2.c
+++ b/lib/getndelim2.c
@@ -76,7 +76,7 @@
   ssize_t bytes_stored = -1;
   char *ptr = *lineptr;
   size_t size = *linesize;
-  bool done = false;
+  bool found_delimiter;
 
   if (!ptr)
     {
@@ -103,7 +103,8 @@
 
   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 @@
 	      if (end)
 		{
 		  buffer_len = end - buffer + 1;
-		  done = true;
+		  found_delimiter = true;
 		}
 	    }
 	}
@@ -137,7 +138,7 @@
 		break;
 	    }
 	  if (c == delim1 || c == delim2)
-	    done = true;
+	    found_delimiter = true;
 	  buffer_len = 1;
 	}
 
@@ -145,13 +146,18 @@
 	 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 @@
       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.  */