Hi all,

While doing addition testing for the subject mentioned PR I discovered numerous
un-freed memory allocations. I reported the problem in comment 30 of the PR.

The attached patch cleans this up by opening the internal unit structures during
program initialization and allowing the automatic closure similar to
pre-connected units. The internal stream structures are created and freed at the
beginning and end of each I/O operation.  I fix a few loose ends.

Regression tested on x86_64.

OK for trunk?  Also needed for same issue in 7.

Regards,

Jerry

2017-12-11  Jerry DeLisle  <jvdeli...@gcc.gnu.org>

        PR libgfortran/78549
        * io/inquire.c (inquire_via_unit): Adjust test for existence for
        pre-connected internal units.
        * io/transfer.c (finalize_transfer): When done with a transfer
        to internal units, free the format buffer and close the stream.
        (st_read_done): Delete freeing the stream, now handled using
        sclose in finalize_transfer. (st_write_done): Likewise.
        * io/unit.c (get_unit): Return NULL for special reserved unit
        numbers, signifying not accessible to the user.
        (init_units): Insert the two special internal units into the
        unit treap. This makes these unit structures available without
        further allocations for later use by internal unit I/O. These
        units are automatically deleted by normal program termination.
        * unix.c (mem_close): Add a guard check to protect from double free.
diff --git a/libgfortran/io/inquire.c b/libgfortran/io/inquire.c
index 848a08f6157..6ba1224d77c 100644
--- a/libgfortran/io/inquire.c
+++ b/libgfortran/io/inquire.c
@@ -47,7 +47,10 @@ inquire_via_unit (st_parameter_inquire *iqp, gfc_unit *u)
     generate_error (&iqp->common, LIBERROR_INQUIRE_INTERNAL_UNIT, NULL);
 
   if ((cf & IOPARM_INQUIRE_HAS_EXIST) != 0)
-    *iqp->exist = (u != NULL) || (iqp->common.unit >= 0);
+    *iqp->exist = (u != NULL &&
+		   iqp->common.unit != GFC_INTERNAL_UNIT &&
+		   iqp->common.unit != GFC_INTERNAL_UNIT4)
+		|| (iqp->common.unit >= 0);
 
   if ((cf & IOPARM_INQUIRE_HAS_OPENED) != 0)
     *iqp->opened = (u != NULL);
diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c
index 4d7ca7abf7b..211dc349750 100644
--- a/libgfortran/io/transfer.c
+++ b/libgfortran/io/transfer.c
@@ -3985,6 +3985,19 @@ finalize_transfer (st_parameter_dt *dtp)
   next_record (dtp, 1);
 
  done:
+
+  if (dtp->u.p.unit_is_internal)
+    {
+      fbuf_destroy (dtp->u.p.current_unit);
+      if (dtp->u.p.current_unit
+	  && (dtp->u.p.current_unit->child_dtio  == 0)
+	  && dtp->u.p.current_unit->s)
+	{
+	  sclose (dtp->u.p.current_unit->s);
+	  dtp->u.p.current_unit->s = NULL;
+	}
+    }
+
 #ifdef HAVE_USELOCALE
   if (dtp->u.p.old_locale != (locale_t) 0)
     {
@@ -4094,8 +4107,6 @@ st_read_done (st_parameter_dt *dtp)
 	    {
 	      free (dtp->u.p.current_unit->filename);
 	      dtp->u.p.current_unit->filename = NULL;
-	      free (dtp->u.p.current_unit->s);
-	      dtp->u.p.current_unit->s = NULL;
 	      if (dtp->u.p.current_unit->ls)
 		free (dtp->u.p.current_unit->ls);
 	      dtp->u.p.current_unit->ls = NULL;
@@ -4165,8 +4176,6 @@ st_write_done (st_parameter_dt *dtp)
 	    {
 	      free (dtp->u.p.current_unit->filename);
 	      dtp->u.p.current_unit->filename = NULL;
-	      free (dtp->u.p.current_unit->s);
-	      dtp->u.p.current_unit->s = NULL;
 	      if (dtp->u.p.current_unit->ls)
 		free (dtp->u.p.current_unit->ls);
 	      dtp->u.p.current_unit->ls = NULL;
diff --git a/libgfortran/io/unit.c b/libgfortran/io/unit.c
index 66cd12dcdcd..2ca8525fbec 100644
--- a/libgfortran/io/unit.c
+++ b/libgfortran/io/unit.c
@@ -566,7 +566,11 @@ get_unit (st_parameter_dt *dtp, int do_create)
      is not allowed, such units must be created with
      OPEN(NEWUNIT=...).  */
   if (dtp->common.unit < 0)
-    return get_gfc_unit (dtp->common.unit, 0);
+    {
+      if (dtp->common.unit > NEWUNIT_START) /* Reserved units.  */
+	return NULL;
+      return get_gfc_unit (dtp->common.unit, 0);
+    }
 
   return get_gfc_unit (dtp->common.unit, do_create);
 }
@@ -701,6 +705,9 @@ init_units (void)
 
       __gthread_mutex_unlock (&u->lock);
     }
+  /* The default internal units.  */
+  u = insert_unit (GFC_INTERNAL_UNIT);
+  u = insert_unit (GFC_INTERNAL_UNIT4);
 }
 
 
diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c
index 61e9f7997b2..a07a3c9cea8 100644
--- a/libgfortran/io/unix.c
+++ b/libgfortran/io/unix.c
@@ -962,8 +962,8 @@ mem_flush (unix_stream *s __attribute__ ((unused)))
 static int
 mem_close (unix_stream *s)
 {
-  free (s);
-
+  if (s)
+    free (s);
   return 0;
 }
 

Reply via email to