Patchwork Fix libgfortran read_sf (PR fortran/47878)

login
register
mail settings
Submitter Jakub Jelinek
Date Feb. 24, 2011, 8:16 p.m.
Message ID <20110224201635.GT30899@tyan-ft48-01.lab.bos.redhat.com>
Download mbox | patch
Permalink /patch/84473/
State New
Headers show

Comments

Jakub Jelinek - Feb. 24, 2011, 8:16 p.m.
Hi!

read_sf can return pointer to already freed memory (in case fbuf_getc
results in realloc).  The following patch fixes it, bootstrapped/regtested
on x86_64-linux and i686-linux, approved by Jerry in the PR, committed to
trunk.

2011-02-24  Jakub Jelinek  <jakub@redhat.com>

	PR fortran/47878
	* io/transfer.c (read_sf): Call fbuf_getptr only at the end,
	and subtract n, dtp->u.p.sf_seen_eor and seen_comma from it.

	* gfortran.dg/pr47878.f90: New test.


	Jakub
Jerry DeLisle - Feb. 25, 2011, 12:52 p.m.
On 02/24/2011 12:16 PM, Jakub Jelinek wrote:
> Hi!
>
> read_sf can return pointer to already freed memory (in case fbuf_getc
> results in realloc).  The following patch fixes it, bootstrapped/regtested
> on x86_64-linux and i686-linux, approved by Jerry in the PR, committed to
> trunk.

Thanks for fixing this Jakub. Your support is greatly appreciated by the whole team.

Jerry

Patch

--- libgfortran/io/transfer.c.jj	2011-02-24 17:33:39.000000000 +0100
+++ libgfortran/io/transfer.c	2011-02-24 18:17:41.000000000 +0100
@@ -284,7 +284,6 @@  static char *
 read_sf (st_parameter_dt *dtp, int * length)
 {
   static char *empty_string[0];
-  char *base;
   int q, q2;
   int n, lorig, seen_comma;
 
@@ -302,9 +301,6 @@  read_sf (st_parameter_dt *dtp, int * len
 
   /* Read data into format buffer and scan through it.  */
   lorig = *length;
-  base = fbuf_getptr (dtp->u.p.current_unit);
-  if (base == NULL)
-    return NULL;
 
   while (n < *length)
     {
@@ -396,7 +392,12 @@  read_sf (st_parameter_dt *dtp, int * len
   if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
     dtp->u.p.size_used += (GFC_IO_INT) n;
 
-  return base;
+  /* We can't call fbuf_getptr before the loop doing fbuf_getc, because
+     fbuf_getc might reallocate the buffer.  So return current pointer
+     minus all the advances, which is n plus up to two characters
+     of newline or comma.  */
+  return fbuf_getptr (dtp->u.p.current_unit)
+	 - n - dtp->u.p.sf_seen_eor - seen_comma;
 }
 
 
--- gcc/testsuite/gfortran.dg/pr47878.f90.jj	2011-02-24 18:12:03.000000000 +0100
+++ gcc/testsuite/gfortran.dg/pr47878.f90	2011-02-24 18:12:59.000000000 +0100
@@ -0,0 +1,10 @@ 
+! PR fortran/47878
+! { dg-do run }
+  integer :: a(5)
+  open (99, recl = 40)
+  write (99, '(5i3)') 1, 2, 3
+  rewind (99)
+  read (99, '(5i3)') a
+  if (any (a.ne.(/1, 2, 3, 0, 0/))) call abort 
+  close (99, status = 'delete')
+end