re PR libfortran/32702 (crash when printing big character variable)
authorJerry DeLisle <jvdelisle@gcc.gnu.org>
Tue, 10 Jul 2007 05:37:29 +0000 (05:37 +0000)
committerJerry DeLisle <jvdelisle@gcc.gnu.org>
Tue, 10 Jul 2007 05:37:29 +0000 (05:37 +0000)
2007-07-09  Jerry DeLisle  <jvdelisle@gcc.gnu.org>

PR libgfortran/32702
* io/unix.c (unix_stream): Restore buffer pointer and small_buffer.
(fd_alloc): If the number of bytes needed is greater than the default
BUFFER_SIZE, allocate a new buffer large enough.  Free the old buffer if
necessary. (fd_sfree): Restore use of buffer pointer.
(fd_close): Likewise. (fd_open): Likewise.
(init_error_stream): Likewise.

From-SVN: r126510

libgfortran/ChangeLog
libgfortran/io/unix.c

index 154d241..25b5d4c 100644 (file)
@@ -1,3 +1,13 @@
+2007-07-09  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
+
+       PR libgfortran/32702
+       * io/unix.c (unix_stream): Restore buffer pointer and small_buffer.
+       (fd_alloc): If the number of bytes needed is greater than the default
+       BUFFER_SIZE, allocate a new buffer large enough.  Free the old buffer if
+       necessary. (fd_sfree): Restore use of buffer pointer.
+       (fd_close): Likewise. (fd_open): Likewise.
+       (init_error_stream): Likewise.
+       
 2007-07-09  Thomas Koenig  <tkoenig@gcc.gnu.org>
 
        PR libfortran/32336
index 39ee87d..bdfd245 100644 (file)
@@ -97,6 +97,7 @@ typedef struct
   gfc_offset dirty_offset;     /* Start of modified bytes in buffer */
   gfc_offset file_length;      /* Length of the file, -1 if not seekable. */
 
+  char *buffer;
   int len;                     /* Physical length of the current buffer */
   int active;                  /* Length of valid bytes in the buffer */
 
@@ -107,7 +108,7 @@ typedef struct
 
   int unbuffered;               /* =1 if the stream is not buffered */
 
-  char buffer[BUFFER_SIZE];
+  char small_buffer[BUFFER_SIZE];
 }
 unix_stream;
 
@@ -437,17 +438,29 @@ static void
 fd_alloc (unix_stream * s, gfc_offset where,
          int *len __attribute__ ((unused)))
 {
-  int n;
+  char *new_buffer;
+  int n, read_len;
+
+  if (*len <= BUFFER_SIZE)
+    {
+      new_buffer = s->small_buffer;
+      read_len = BUFFER_SIZE;
+    }
+  else
+    {
+      new_buffer = get_mem (*len);
+      read_len = *len;
+    }
 
   /* Salvage bytes currently within the buffer.  This is important for
    * devices that cannot seek. */
 
-  if (s->buffer_offset <= where &&
+  if (s->buffer != NULL && s->buffer_offset <= where &&
       where <= s->buffer_offset + s->active)
     {
 
       n = s->active - (where - s->buffer_offset);
-      memmove (s->buffer, s->buffer + (where - s->buffer_offset), n);
+      memmove (new_buffer, s->buffer + (where - s->buffer_offset), n);
 
       s->active = n;
     }
@@ -458,7 +471,13 @@ fd_alloc (unix_stream * s, gfc_offset where,
 
   s->buffer_offset = where;
 
-  s->len = BUFFER_SIZE;
+  /* free the old buffer if necessary */
+
+  if (s->buffer != NULL && s->buffer != s->small_buffer)
+    free_mem (s->buffer);
+
+  s->buffer = new_buffer;
+  s->len = read_len;
 }
 
 
@@ -590,7 +609,8 @@ static try
 fd_sfree (unix_stream * s)
 {
   if (s->ndirty != 0 &&
-      (options.all_unbuffered || s->unbuffered))
+      (s->buffer != s->small_buffer || options.all_unbuffered ||
+       s->unbuffered))
     return fd_flush (s);
 
   return SUCCESS;
@@ -791,6 +811,9 @@ fd_close (unix_stream * s)
   if (fd_flush (s) == FAILURE)
     return FAILURE;
 
+  if (s->buffer != NULL && s->buffer != s->small_buffer)
+    free_mem (s->buffer);
+
   if (s->fd != STDOUT_FILENO && s->fd != STDERR_FILENO)
     {
       if (close (s->fd) < 0)
@@ -819,6 +842,7 @@ fd_open (unix_stream * s)
   s->st.write = (void *) fd_write;
   s->st.set = (void *) fd_sset;
 
+  s->buffer = NULL;
 }
 
 
@@ -1377,6 +1401,7 @@ init_error_stream (unix_stream *error)
   error->st.sfree = (void *) fd_sfree;
 
   error->unbuffered = 1;
+  error->buffer = error->small_buffer;
 
   return (stream *) error;
 }