This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch, libgfortran] PR43265 Follow-up patch for several corner cases


Hi Folks,

I hope this gets them all. This patch corrects a number of deficiencies related to end of file conditions with no record markers or with padding.

I believe the ChangeLog entry explains it well enough. The two attached test cases capture the essence of the problems. The two namelist test cases are changed only to prevent an infinite loop if down the road we break this. (Found when developing the patch).

While at it, I factored the code a little. This helped to isolate internal from external code during debugging and seemed to make sense to do.

Regression tested on x86-64-linux-gnu.

OK for trunk and then backport to 4.4

Regards,

Jerry

2010-03-16 Jerry DeLisle <jvdelisle@gcc.gnu.org>

	PR libfortran/43265
	* io/io.h: Delete prototype for read_sf, making it static.
	* io/read.c (read_x): Modify to call hit_eof if PAD="no".
	* io/transfer.c (read_sf_internal): New static function extracted from
	read_sf for use on internal units only.
	(read_sf): New factoring of this function, make it static.  Add special
	conditions for EOF based on ADVANCE="no", PAD="no", and whether any
	bytes have been previously read from the record.
	(read_block_form): Modify to call read_sf or read_sf_internal.
	(next_record_r): Add a done flag similar to next_record_w. Call hit_eof
	if internal array unit next record returns finished, meaning an EOF was
	found and not done, ie not the last record expected.  For external
	units call hit_eof if item_count is 1 or there are no pending spaces.
	(next_record): Update call to next_record_r.
Index: read.c
===================================================================
--- read.c	(revision 157452)
+++ read.c	(working copy)
@@ -1047,11 +1047,22 @@ read_x (st_parameter_dt *dtp, int n)
     }
 
   p = fbuf_read (dtp->u.p.current_unit, &length);
-  if (p == NULL || (length == 0 && dtp->u.p.item_count == 1))
+  if (p == NULL)
     {
       hit_eof (dtp);
       return;
     }
+  
+  if (length == 0 && dtp->u.p.item_count == 1)
+    {
+      if (dtp->u.p.current_unit->pad_status == PAD_NO)
+	{
+	  hit_eof (dtp);
+	  return;
+	}
+      else
+	return;
+    }
 
   n = 0;
   while (n < length)
Index: io.h
===================================================================
--- io.h	(revision 157452)
+++ io.h	(working copy)
@@ -642,9 +642,6 @@ internal_proto(type_name);
 extern void * read_block_form (st_parameter_dt *, int *);
 internal_proto(read_block_form);
 
-extern char *read_sf (st_parameter_dt *, int *);
-internal_proto(read_sf);
-
 extern void *write_block (st_parameter_dt *, int);
 internal_proto(write_block);
 
Index: transfer.c
===================================================================
--- transfer.c	(revision 157452)
+++ transfer.c	(working copy)
@@ -175,9 +175,7 @@ current_mode (st_parameter_dt *dtp)
 }
 
 
-/* Mid level data transfer statements.  These subroutines do reading
-   and writing in the style of salloc_r()/salloc_w() within the
-   current record.  */
+/* Mid level data transfer statements.  */
 
 /* When reading sequential formatted records we have a problem.  We
    don't know how long the line is until we read the trailing newline,
@@ -190,13 +188,15 @@ current_mode (st_parameter_dt *dtp)
    we hit the newline.  For small allocations, we use a static buffer.
    For larger allocations, we are forced to allocate memory on the
    heap.  Hopefully this won't happen very often.  */
+   
+/* Read sequential file - internal unit  */
 
-char *
-read_sf (st_parameter_dt *dtp, int * length)
+static char *
+read_sf_internal (st_parameter_dt *dtp, int * length)
 {
   static char *empty_string[0];
-  char *base, *p, q;
-  int n, lorig, memread, seen_comma;
+  char *base;
+  int lorig;
 
   /* If we have seen an eor previously, return a length of 0.  The
      caller is responsible for correctly padding the input field.  */
@@ -208,19 +208,42 @@ current_mode (st_parameter_dt *dtp)
       return (char*) empty_string;
     }
 
-  if (is_internal_unit (dtp))
+  lorig = *length;
+  base = mem_alloc_r (dtp->u.p.current_unit->s, length);
+  if (unlikely (lorig > *length))
     {
-      memread = *length;
-      base = mem_alloc_r (dtp->u.p.current_unit->s, length);
-      if (unlikely (memread > *length))
-	{
-          hit_eof (dtp);
-	  return NULL;
-	}
-      n = *length;
-      goto done;
+      hit_eof (dtp);
+      return NULL;
     }
 
+  dtp->u.p.current_unit->bytes_left -= *length;
+
+  if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
+    dtp->u.p.size_used += (GFC_IO_INT) *length;
+
+  return base;
+
+}
+
+/* Read sequential file - external unit */
+
+static char *
+read_sf (st_parameter_dt *dtp, int * length)
+{
+  static char *empty_string[0];
+  char *base, *p, q;
+  int n, lorig, seen_comma;
+
+  /* If we have seen an eor previously, return a length of 0.  The
+     caller is responsible for correctly padding the input field.  */
+  if (dtp->u.p.sf_seen_eor)
+    {
+      *length = 0;
+      /* Just return something that isn't a NULL pointer, otherwise the
+         caller thinks an error occured.  */
+      return (char*) empty_string;
+    }
+
   n = seen_comma = 0;
 
   /* Read data into format buffer and scan through it.  */
@@ -307,11 +330,14 @@ current_mode (st_parameter_dt *dtp)
 	  else
 	    dtp->u.p.at_eof = 1;
 	}
-      else
-        {
-          hit_eof (dtp);
-          return NULL;
-        }
+      else if (dtp->u.p.advance_status == ADVANCE_NO
+	       || dtp->u.p.current_unit->pad_status == PAD_NO
+	       || dtp->u.p.current_unit->bytes_left
+		    == dtp->u.p.current_unit->recl)
+	{
+	  hit_eof (dtp);
+	  return NULL;
+	}
     }
 
  done:
@@ -352,7 +378,8 @@ read_block_form (st_parameter_dt *dtp, int * nbyte
             dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
 	  else
 	    {
-	      if (unlikely (dtp->u.p.current_unit->pad_status == PAD_NO))
+	      if (unlikely (dtp->u.p.current_unit->pad_status == PAD_NO)
+		  && !is_internal_unit (dtp))
 		{
 		  /* Not enough data left.  */
 		  generate_error (&dtp->common, LIBERROR_EOR, NULL);
@@ -360,9 +387,10 @@ read_block_form (st_parameter_dt *dtp, int * nbyte
 		}
 	    }
 
-	  if (unlikely (dtp->u.p.current_unit->bytes_left == 0))
+	  if (unlikely (dtp->u.p.current_unit->bytes_left == 0
+	      && !is_internal_unit(dtp)))
 	    {
-              hit_eof (dtp);
+	      hit_eof (dtp);
 	      return NULL;
 	    }
 
@@ -374,7 +402,11 @@ read_block_form (st_parameter_dt *dtp, int * nbyte
       (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL ||
        dtp->u.p.current_unit->flags.access == ACCESS_STREAM))
     {
-      source = read_sf (dtp, nbytes);
+      if (is_internal_unit (dtp))
+	source = read_sf_internal (dtp, nbytes);
+      else
+	source = read_sf (dtp, nbytes);
+
       dtp->u.p.current_unit->strm_pos +=
 	(gfc_offset) (*nbytes + dtp->u.p.sf_seen_eor);
       return source;
@@ -2731,7 +2763,7 @@ min_off (gfc_offset a, gfc_offset b)
 /* Space to the next record for read mode.  */
 
 static void
-next_record_r (st_parameter_dt *dtp)
+next_record_r (st_parameter_dt *dtp, int done)
 {
   gfc_offset record;
   int bytes_left;
@@ -2758,10 +2790,9 @@ static void
     case FORMATTED_SEQUENTIAL:
       /* read_sf has already terminated input because of an '\n', or
          we have hit EOF.  */
-      if (dtp->u.p.sf_seen_eor || dtp->u.p.at_eof)
+      if (dtp->u.p.sf_seen_eor)
 	{
 	  dtp->u.p.sf_seen_eor = 0;
-          dtp->u.p.at_eof = 0;
 	  break;
 	}
 
@@ -2773,6 +2804,8 @@ static void
 
 	      record = next_array_record (dtp, dtp->u.p.current_unit->ls,
 					  &finished);
+	      if (!done && finished)
+		hit_eof (dtp);
 
 	      /* Now seek to this record.  */
 	      record = record * dtp->u.p.current_unit->recl;
@@ -2810,7 +2843,8 @@ static void
 		{
                   if (errno != 0)
                     generate_error (&dtp->common, LIBERROR_OS, NULL);
-		  else if (dtp->u.p.item_count == 1)
+		  else if (dtp->u.p.item_count == 1
+			   || dtp->u.p.pending_spaces == 0)
 		    hit_eof (dtp);
 		  break;
                 }
@@ -3151,7 +3185,7 @@ next_record (st_parameter_dt *dtp, int done)
   dtp->u.p.current_unit->read_bad = 0;
 
   if (dtp->u.p.mode == READING)
-    next_record_r (dtp);
+    next_record_r (dtp, done);
   else
     next_record_w (dtp, done);
 

Attachment: read_empty_file.f
Description: Text document

Attachment: read_eof_all.f90
Description: Text document

Attachment: namelist_27.f90
Description: Text document

Attachment: namelist_28.f90
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]