[Patch, fortran] PR fortran/92621 Problems with memory handling with allocatable intent(out) arrays with bind(c)

José Rui Faustino de Sousa jrfsousa@gmail.com
Fri Feb 21 12:57:00 GMT 2020


Hi all!

Proposed patch to solve problems with memory handling with allocatable 
intent(out) arrays with bind(c).

The patch also seems to affect PR92189.

Patch tested only on x86_64-pc-linux-gnu.

The code currently generated tries to deallocate the artificial cfi.n 
pointer before it is associated with the allocatable array.

Since the cfi.n pointer is uninitialized in some infrequent situations 
(using -static-libgfortran seems to do the trick) the pointer seems to 
contain garbage and a segmentation fault is generated.

Since the deallocation is done prior to the cfi.n pointer being 
associated with the allocatable array the memory is never freed and the 
array will be passed still allocated and consequently attempts to 
allocate it will fail.

A diff of only the main code changes without spacing changes is attached 
to facilitate human reviewing.

Thank you very much.

Best regards,
José Rui

2020-2-21  José Rui Faustino de Sousa  <jrfsousa@gmail.com>

  PR fortran/92621
  * trans-expr.c (gfc_conv_gfc_desc_to_cfi_desc): Add code to deallocate
  allocatable intent(out) dummy array arguments, slightly rearrange code.
  (gfc_conv_procedure_call): Split if conditional in two branches removes
  unnecessary checks for is_bind_c and obsolete comments from second
  branch.

2020-02-21  José Rui Faustino de Sousa  <jrfsousa@gmail.com>

  PR fortran/92621
  * bind-c-intent-out.f90: Changes dg-do compile to run, changes regex to
  match the changes in code generation.

2020-02-21  José Rui Faustino de Sousa  <jrfsousa@gmail.com>

  PR fortran/92621
  * PR92621.f90: New test.


diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 5825a4b..70dd9be 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -5248,6 +5248,39 @@ gfc_conv_gfc_desc_to_cfi_desc (gfc_se *parmse, 
gfc_expr *e, gfc_symbol *fsym)
        if (POINTER_TYPE_P (TREE_TYPE (parmse->expr)))
  	parmse->expr = build_fold_indirect_ref_loc (input_location,
  						    parmse->expr);
+    }
+  else
+    gfc_conv_expr (parmse, e);
+
+  if (POINTER_TYPE_P (TREE_TYPE (parmse->expr)))
+    parmse->expr = build_fold_indirect_ref_loc (input_location,
+						parmse->expr);
+
+  /* If an ALLOCATABLE dummy argument has INTENT(OUT) and is
+     allocated on entry, it must be deallocated.  */
+  if (fsym && fsym->attr.allocatable
+      && fsym->attr.intent == INTENT_OUT)
+    {
+      tmp = parmse->expr;
+
+      if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (tmp)))
+	tmp = gfc_conv_descriptor_data_get (tmp);
+      tmp = gfc_deallocate_with_status (tmp, NULL_TREE, NULL_TREE,
+					NULL_TREE, NULL_TREE, true,
+					e,
+					GFC_CAF_COARRAY_NOCOARRAY);
+      if (fsym->attr.optional
+	  && e->expr_type == EXPR_VARIABLE
+	  && e->symtree->n.sym->attr.optional)
+	tmp = fold_build3_loc (input_location, COND_EXPR,
+			       void_type_node,
+			       gfc_conv_expr_present (e->symtree->n.sym),
+			       tmp, build_empty_stmt (input_location));
+      gfc_add_expr_to_block (&parmse->pre, tmp);
+    }
+	
+  if (e->rank != 0)
+    {
        bool is_artificial = (INDIRECT_REF_P (parmse->expr)
  			    ? DECL_ARTIFICIAL (TREE_OPERAND (parmse->expr, 0))
  			    : DECL_ARTIFICIAL (parmse->expr));
@@ -5293,16 +5326,8 @@ gfc_conv_gfc_desc_to_cfi_desc (gfc_se *parmse, 
gfc_expr *e, gfc_symbol *fsym)
  	}
      }
    else
-    {
-      gfc_conv_expr (parmse, e);
-
-      if (POINTER_TYPE_P (TREE_TYPE (parmse->expr)))
-	parmse->expr = build_fold_indirect_ref_loc (input_location,
-						    parmse->expr);
-
-      parmse->expr = gfc_conv_scalar_to_descriptor (parmse,
-						    parmse->expr, attr);
-    }
+    parmse->expr = gfc_conv_scalar_to_descriptor (parmse,
+						  parmse->expr, attr);

    /* Set the CFI attribute field through a temporary value for the
       gfc attribute.  */
@@ -6170,113 +6195,113 @@ gfc_conv_procedure_call (gfc_se * se, 
gfc_symbol * sym,
  		/* Implement F2018, C.12.6.1: paragraph (2).  */
  		gfc_conv_gfc_desc_to_cfi_desc (&parmse, e, fsym);

-	      else if (e->expr_type == EXPR_VARIABLE
-		    && is_subref_array (e)
-		    && !(fsym && fsym->attr.pointer))
-		/* The actual argument is a component reference to an
-		   array of derived types.  In this case, the argument
-		   is converted to a temporary, which is passed and then
-		   written back after the procedure call.  */
-		gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
-				fsym ? fsym->attr.intent : INTENT_INOUT,
-				fsym && fsym->attr.pointer);
-
-	      else if (gfc_is_class_array_ref (e, NULL)
-		       && fsym && fsym->ts.type == BT_DERIVED)
-		/* The actual argument is a component reference to an
-		   array of derived types.  In this case, the argument
-		   is converted to a temporary, which is passed and then
-		   written back after the procedure call.
-		   OOP-TODO: Insert code so that if the dynamic type is
-		   the same as the declared type, copy-in/copy-out does
-		   not occur.  */
-		gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
-					   fsym->attr.intent,
-					   fsym->attr.pointer);
-
-	      else if (gfc_is_class_array_function (e)
-		       && fsym && fsym->ts.type == BT_DERIVED)
-		/* See previous comment.  For function actual argument,
-		   the write out is not needed so the intent is set as
-		   intent in.  */
-		{
-		  e->must_finalize = 1;
-		  gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
-					     INTENT_IN, fsym->attr.pointer);
-		}
-	      else if (fsym && fsym->attr.contiguous
-		       && !gfc_is_simply_contiguous (e, false, true)
-		       && gfc_expr_is_variable (e))
-		{
-		  gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
-					     fsym->attr.intent,
-					     fsym->attr.pointer);
-		}
  	      else
-		gfc_conv_array_parameter (&parmse, e, nodesc_arg, fsym,
-					  sym->name, NULL);
-
-	      /* Unallocated allocatable arrays and unassociated pointer arrays
-		 need their dtype setting if they are argument associated with
-		 assumed rank dummies.  */
-	      if (!sym->attr.is_bind_c && e && fsym && fsym->as
-		  && fsym->as->type == AS_ASSUMED_RANK)
  		{
-		  if (gfc_expr_attr (e).pointer
-		      || gfc_expr_attr (e).allocatable)
-		    set_dtype_for_unallocated (&parmse, e);
-		  else if (e->expr_type == EXPR_VARIABLE
-			   && e->symtree->n.sym->attr.dummy
-			   && e->symtree->n.sym->as
-			   && e->symtree->n.sym->as->type == AS_ASSUMED_SIZE)
+		  if (e->expr_type == EXPR_VARIABLE
+		      && is_subref_array (e)
+		      && !(fsym && fsym->attr.pointer))
+		    /* The actual argument is a component reference to an
+		       array of derived types.  In this case, the argument
+		       is converted to a temporary, which is passed and then
+		       written back after the procedure call.  */
+		    gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
+					       fsym ? fsym->attr.intent : INTENT_INOUT,
+					       fsym && fsym->attr.pointer);
+
+		  else if (gfc_is_class_array_ref (e, NULL)
+			   && fsym && fsym->ts.type == BT_DERIVED)
+		    /* The actual argument is a component reference to an
+		       array of derived types.  In this case, the argument
+		       is converted to a temporary, which is passed and then
+		       written back after the procedure call.
+		       OOP-TODO: Insert code so that if the dynamic type is
+		       the same as the declared type, copy-in/copy-out does
+		       not occur.  */
+		    gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
+					       fsym->attr.intent,
+					       fsym->attr.pointer);
+
+		  else if (gfc_is_class_array_function (e)
+			   && fsym && fsym->ts.type == BT_DERIVED)
+		    /* See previous comment.  For function actual argument,
+		       the write out is not needed so the intent is set as
+		       intent in.  */
  		    {
-		      tree minus_one;
-		      tmp = build_fold_indirect_ref_loc (input_location,
-							 parmse.expr);
-		      minus_one = build_int_cst (gfc_array_index_type, -1);
-		      gfc_conv_descriptor_ubound_set (&parmse.pre, tmp,
-						      gfc_rank_cst[e->rank - 1],
-						      minus_one);
- 		    }
-		}
+		      e->must_finalize = 1;
+		      gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
+						 INTENT_IN, fsym->attr.pointer);
+		    }
+		  else if (fsym && fsym->attr.contiguous
+			   && !gfc_is_simply_contiguous (e, false, true)
+			   && gfc_expr_is_variable (e))
+		    {
+		      gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
+						 fsym->attr.intent,
+						 fsym->attr.pointer);
+		    }
+		  else
+		    gfc_conv_array_parameter (&parmse, e, nodesc_arg, fsym,
+					      sym->name, NULL);
+
+		  /* Unallocated allocatable arrays and unassociated pointer arrays
+		     need their dtype setting if they are argument associated with
+		     assumed rank dummies.  */
+		  if (e && fsym && fsym->as
+		      && fsym->as->type == AS_ASSUMED_RANK)
+		    {
+		      if (gfc_expr_attr (e).pointer
+			  || gfc_expr_attr (e).allocatable)
+			set_dtype_for_unallocated (&parmse, e);
+		      else if (e->expr_type == EXPR_VARIABLE
+			       && e->symtree->n.sym->attr.dummy
+			       && e->symtree->n.sym->as
+			       && e->symtree->n.sym->as->type == AS_ASSUMED_SIZE)
+			{
+			  tree minus_one;
+			  tmp = build_fold_indirect_ref_loc (input_location,
+							     parmse.expr);
+			  minus_one = build_int_cst (gfc_array_index_type, -1);
+			  gfc_conv_descriptor_ubound_set (&parmse.pre, tmp,
+							  gfc_rank_cst[e->rank - 1],
+							  minus_one);
+			}
+		    }

-	      /* If an ALLOCATABLE dummy argument has INTENT(OUT) and is
-		 allocated on entry, it must be deallocated.  */
-	      if (fsym && fsym->attr.allocatable
-		  && fsym->attr.intent == INTENT_OUT)
-		{
-		  if (fsym->ts.type == BT_DERIVED
-		      && fsym->ts.u.derived->attr.alloc_comp)
-		  {
-		    // deallocate the components first
-		    tmp = gfc_deallocate_alloc_comp (fsym->ts.u.derived,
-						     parmse.expr, e->rank);
-		    if (tmp != NULL_TREE)
+		  /* If an ALLOCATABLE dummy argument has INTENT(OUT) and is
+		     allocated on entry, it must be deallocated.  */
+		  if (fsym && fsym->attr.allocatable
+		      && fsym->attr.intent == INTENT_OUT)
+		    {
+		      if (fsym->ts.type == BT_DERIVED
+			  && fsym->ts.u.derived->attr.alloc_comp)
+			{
+			  // deallocate the components first
+			  tmp = gfc_deallocate_alloc_comp (fsym->ts.u.derived,
+							   parmse.expr, e->rank);
+			  if (tmp != NULL_TREE)
+			    gfc_add_expr_to_block (&se->pre, tmp);
+			}
+
+		      tmp = parmse.expr;
+
+		      if  (TREE_TYPE(tmp) != pvoid_type_node)
+			tmp = build_fold_indirect_ref_loc (input_location,
+							   parmse.expr);
+		      if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (tmp)))
+			tmp = gfc_conv_descriptor_data_get (tmp);
+		      tmp = gfc_deallocate_with_status (tmp, NULL_TREE, NULL_TREE,
+							NULL_TREE, NULL_TREE, true,
+							e,
+							GFC_CAF_COARRAY_NOCOARRAY);
+		      if (fsym->attr.optional
+			  && e->expr_type == EXPR_VARIABLE
+			  && e->symtree->n.sym->attr.optional)
+			tmp = fold_build3_loc (input_location, COND_EXPR,
+					       void_type_node,
+					       gfc_conv_expr_present (e->symtree->n.sym),
+					       tmp, build_empty_stmt (input_location));
  		      gfc_add_expr_to_block (&se->pre, tmp);
-		  }
-
-		  tmp = parmse.expr;
-		  /* With bind(C), the actual argument is replaced by a bind-C
-		     descriptor; in this case, the data component arrives here,
-		     which shall not be dereferenced, but still freed and
-		     nullified.  */
-		  if  (TREE_TYPE(tmp) != pvoid_type_node)
-		    tmp = build_fold_indirect_ref_loc (input_location,
-						       parmse.expr);
-		  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (tmp)))
-		    tmp = gfc_conv_descriptor_data_get (tmp);
-		  tmp = gfc_deallocate_with_status (tmp, NULL_TREE, NULL_TREE,
-						    NULL_TREE, NULL_TREE, true,
-						    e,
-						    GFC_CAF_COARRAY_NOCOARRAY);
-		  if (fsym->attr.optional
-		      && e->expr_type == EXPR_VARIABLE
-		      && e->symtree->n.sym->attr.optional)
-		    tmp = fold_build3_loc (input_location, COND_EXPR,
-				     void_type_node,
-				     gfc_conv_expr_present (e->symtree->n.sym),
-				       tmp, build_empty_stmt (input_location));
-		  gfc_add_expr_to_block (&se->pre, tmp);
+		    }
  		}
  	    }
  	}
diff --git a/gcc/testsuite/gfortran.dg/PR92621.f90 
b/gcc/testsuite/gfortran.dg/PR92621.f90
new file mode 100644
index 0000000..9ca2e70
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/PR92621.f90
@@ -0,0 +1,41 @@
+! { dg-do run }
+! { dg-options "-static-libgfortran" }
+!
+! PR fortran/92621
+!
+
+subroutine hello(val) bind(c)
+  use, intrinsic :: iso_c_binding, only: c_int
+
+  implicit none
+
+  integer(kind=c_int), allocatable, intent(out) :: val(:)
+
+  allocate(val(1))
+  val = 2
+  return
+end subroutine hello
+
+program alloc_p
+
+  use, intrinsic :: iso_c_binding, only: c_int
+
+  implicit none
+
+  interface
+    subroutine hello(val) bind(c)
+      import :: c_int
+      implicit none
+      integer(kind=c_int), allocatable, intent(out) :: val(:)
+    end subroutine hello
+  end interface
+
+  integer(kind=c_int), allocatable :: a(:)
+
+  allocate(a(1))
+  a = 1
+  call hello(a)
+  stop
+
+end program alloc_p
+
diff --git a/gcc/testsuite/gfortran.dg/bind-c-intent-out.f90 
b/gcc/testsuite/gfortran.dg/bind-c-intent-out.f90
index 39822c0..470afb8 100644
--- a/gcc/testsuite/gfortran.dg/bind-c-intent-out.f90
+++ b/gcc/testsuite/gfortran.dg/bind-c-intent-out.f90
@@ -1,4 +1,4 @@
-! { dg-do compile }
+! { dg-do run }
  ! { dg-options "-fdump-tree-original" }
  !
  ! PR fortran/91863
@@ -38,5 +38,7 @@ end program p
  ! As cfi (i.e. the descriptor itself) is allocated in libgomp, it has 
to be freed after the call.

  ! { dg-final { scan-tree-dump-times "__builtin_free" 2 "original" } }
-! { dg-final { scan-tree-dump-times "__builtin_free 
\\(cfi\\.\[0-9\]+\\);" 2 "original" } }
-! { dg-final { scan-tree-dump-times "cfi\\.\[0-9\]+ = 0B;" 2 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free \\(\\(void \\*\\) 
a\\.data\\);" 1 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free 
\\(cfi\\.\[0-9\]+\\);" 1 "original" } }
+! { dg-final { scan-tree-dump-times "\\(integer\\(kind\\=4\\)\\\[0:\\\] 
\\* restrict\\) a\\.data = 0B;" 1 "original" } }
+! { dg-final { scan-tree-dump-times "cfi\\.\[0-9\]+ = 0B;" 1 "original" } }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: trans-expr.patch
Type: text/x-patch
Size: 3681 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/fortran/attachments/20200221/59acc2ae/attachment.bin>


More information about the Fortran mailing list