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  <jrfso...@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  <jrfso...@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  <jrfso...@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" } }
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);
-    }
 
   /* Set the CFI attribute field through a temporary value for the
      gfc attribute.  */
@@ -6170,7 +6195,9 @@ 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
+	      else
+		{
+		  if (e->expr_type == EXPR_VARIABLE
 		      && is_subref_array (e)
 		      && !(fsym && fsym->attr.pointer))
 		    /* The actual argument is a component reference to an
@@ -6219,7 +6246,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 		  /* 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
+		  if (e && fsym && fsym->as
 		      && fsym->as->type == AS_ASSUMED_RANK)
 		    {
 		      if (gfc_expr_attr (e).pointer
@@ -6256,10 +6283,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 			}
 
 		      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);
@@ -6280,6 +6304,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 		    }
 		}
 	    }
+	}
 
       /* The case with fsym->attr.optional is that of a user subroutine
 	 with an interface indicating an optional argument.  When we call

Reply via email to