Bug 34199 - segfault for TRANSFER integer to TYPE(C_PTR)
Summary: segfault for TRANSFER integer to TYPE(C_PTR)
Status: RESOLVED DUPLICATE of bug 46974
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: 4.4.6
Assignee: Not yet assigned to anyone
URL:
Keywords: ice-on-valid-code
Depends on:
Blocks: 31237 ISO_C_Binding
  Show dependency treegraph
 
Reported: 2007-11-22 21:48 UTC by Tobias Burnus
Modified: 2010-12-19 11:24 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2008-02-24 14:04:05


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Burnus 2007-11-22 21:48:41 UTC
Found by James Van Buskirk at
http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/c8dd08d6da052499/

The following program gives an ICE in transfer; one may argue whether it is valid or not, but I would expect that it works on all systems.

The crash occurs in:

==28354==    at 0x477713: gfc_interpret_derived (target-memory.c:422)
==28354==    by 0x4773DE: gfc_target_interpret_expr (target-memory.c:474)
==28354==    by 0x46AA47: gfc_simplify_transfer (simplify.c:4103)
==28354==    by 0x42A6A2: do_simplify (intrinsic.c:3186)

which is:
      ptr = TREE_INT_CST_LOW (DECL_FIELD_OFFSET (cmp->backend_decl));

Using NAG f95 and ifort, it works and prints ".FALSE.".


program bug2_transfer
   use ISO_C_BINDING
   implicit none
   type(C_PTR) C_NULL_PTR1

   C_NULL_PTR1 = transfer(0_C_INTPTR_T, C_NULL_PTR1)
!   write(*,'(a)') trim(merge('.TRUE. ','.FALSE.', &
!      C_ASSOCIATED(C_NULL_PTR1)))
end program bug2_transfer
Comment 1 Tobias Burnus 2007-11-24 23:02:58 UTC
Some debugging notes. While the following crashes
   C_NULL_PTR1 = transfer(0_C_INTPTR_T, C_NULL_PTR1)
it works after replacing the constant by a variable.

In gfc_simplify_transfer (for the constant expression),
  /* And read the buffer back into the new expression.  */
  gfc_target_interpret_expr (buffer, buffer_size, result);
is called. Here, "result" is of the type(c_ptr), i.e. ts.type == BT_DERIVED.
As it is not a real derived type calling gfc_interpret_derived fails (segfault); converting it into INTEGER works in principle, but it fails in the "C_NULL_PTR1 =" assignment step as one cannot assign an integer to a derived type.
Comment 2 Andrew Pinski 2007-11-25 03:11:32 UTC
Confirmed.
Comment 3 Francois-Xavier Coudert 2008-02-24 14:04:04 UTC
The ICE itself can be gotten rid of by setting the offset of the private field of our ISO_C derived types:

Index: trans-types.c
===================================================================
--- trans-types.c       (revision 132578)
+++ trans-types.c       (working copy)
@@ -1731,6 +1731,7 @@
                                 get_identifier (derived->components->name),
                                 gfc_typenode_for_spec (
                                   &(derived->components->ts)));
+      DECL_FIELD_OFFSET (derived->components->backend_decl) = size_int (0);
 
       derived->ts.kind = gfc_index_integer_kind;
       derived->ts.type = BT_INTEGER;


(Independently of the rest, I think that fix is desirable.) However, with that fix, we now error out:

   C_NULL_PTR1 = transfer(0_C_INTPTR_T, C_NULL_PTR1)
                1
Error: Can't convert INTEGER(4) to TYPE(c_ptr) at (1)

The reason for that is that gfc_typenode_for_spec(), which is called from gfc_interpret_derived(), modifies the symbol itself to make it an integer:

      /* If we're dealing with either C_PTR or C_FUNPTR, we modified the
         type and kind to fit a (void *) and the basetype returned was a
         ptr_type_node.  We need to pass up this new information to the
         symbol that was declared of type C_PTR or C_FUNPTR.  */

I have always been wary of this course of actions (magically making the ISO_C_BINDING derived types into scalar integer variables), and in that case it is biting us hard. I have tried to work around this in target-memory.c by a custom-tailored fix:

Index: target-memory.c
===================================================================
--- target-memory.c     (revision 132578)
+++ target-memory.c     (working copy)
@@ -379,7 +379,21 @@
   /* The attributes of the derived type need to be bolted to the floor.  */
   result->expr_type = EXPR_STRUCTURE;
 
-  type = gfc_typenode_for_spec (&result->ts);
+  /* FIXME -- This is more of a workaround than a real fix, please see
+     PR34199 for details.
+     For ISO_C_BINDING derived types, gfc_typenode_for_spec() will change
+     the symbol under our feet into an integer, which we don't want, so
+     we restore it.  */
+  if (result->ts.type == BT_DERIVED && result->ts.derived->attr.is_iso_c)
+    {
+      gfc_typespec ts;
+      ts = result->ts;
+      type = gfc_typenode_for_spec (&result->ts);
+      result->ts = ts;
+    }
+  else
+    type = gfc_typenode_for_spec (&result->ts);
+
   cmp = result->ts.derived->components;
 
   /* Run through the derived type components.  */


This in turn makes the derived type constructors go into trans-expr.c's gfc_conv_expr(), which does not deal with them. This is fixed with the following patchlet:

Index: trans-expr.c
===================================================================
--- trans-expr.c        (revision 132578)
+++ trans-expr.c        (working copy)
@@ -3517,14 +3517,19 @@
     }
 
   /* We need to convert the expressions for the iso_c_binding derived types.
-     C_NULL_PTR and C_NULL_FUNPTR will be made EXPR_NULL, which evaluates to
-     null_pointer_node.  C_PTR and C_FUNPTR are converted to match the
-     typespec for the C_PTR and C_FUNPTR symbols, which has already been
-     updated to be an integer with a kind equal to the size of a (void *).  */
+     C_NULL_PTR, C_NULL_FUNPTR and constants (coming, for example, from the
+     simplification of TRANSFER expressions) will be made EXPR_NULL,
+     which evaluates to null_pointer_node.  C_PTR and C_FUNPTR are converted
+     to match the typespec for the C_PTR and C_FUNPTR symbols, which has
+     already been updated to be an integer with a kind equal to the size of
+     a (void *).  */
   if (expr->ts.type == BT_DERIVED && expr->ts.derived
       && expr->ts.derived->attr.is_iso_c)
     {
-      if (expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_NULL_PTR
+      /* expr->expr_type == EXPR_STRUCTURE matches the constant derived
+         types.  */
+      if (expr->expr_type == EXPR_STRUCTURE
+         || expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_NULL_PTR
           || expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_NULL_FUNPTR)
         {
          /* Set expr_type to EXPR_NULL, which will result in


Now, with all three patches, we can compile the testcase and run it fine. I'm not really satisfied with the patch to target-memory.c, as it is more a workaround than a patch. For that reason, I'm not assigning this to myself and will let the ISO_C_BINDING experts decide what course is most appropriate.
Comment 4 Francois-Xavier Coudert 2008-02-25 12:08:20 UTC
(In reply to comment #3)
> Now, with all three patches, we can compile the testcase and run it fine.

The three patches, together, regtest fine on x86_64-linux (both -m32 and -m64).
Comment 5 Tobias Burnus 2008-04-28 12:34:34 UTC
Further reports: They might show the same problem, or also different ones. I did not check them all:
http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/c553e0034bab977c

 * * *

Patch by FX:
http://gcc.gnu.org/ml/gcc-patches/2008-03/msg00546.html

My review:
http://gcc.gnu.org/ml/fortran/2008-03/msg00232.html
Comment 6 Francois-Xavier Coudert 2008-05-14 23:24:05 UTC
(In reply to comment #5)
> Patch by FX:
> http://gcc.gnu.org/ml/gcc-patches/2008-03/msg00546.html
> 
> My review:
> http://gcc.gnu.org/ml/fortran/2008-03/msg00232.html

Your second point in the review is spot on, the patch is certainly not doing the right thing (the trans-expr.c part, at least) :(

I've spent some time looking into other options, but this is all too confusing: I wonder if we shouldn't have made these derived types into structures all the way, instead of trying to morph things into pointer types when comes code generation.
Comment 7 Dominique d'Humieres 2008-09-06 19:12:36 UTC
Extracted from http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/c553e0034bab977c
the following code

module bug1 
   use ISO_C_BINDING 
   implicit none 
   contains 
      subroutine sub1(x) 
         type(C_PTR) x 
         write(*,'(z16.16)') transfer(x,0_C_INTPTR_T) 
      end subroutine sub1 
      subroutine sub2(x) 
         type(C_FUNPTR) x 
         write(*,'(z16.16)') transfer(x,0_C_INTPTR_T) 
      end subroutine sub2 
      subroutine sub3() bind(C) 
      end subroutine sub3 
end module bug1 
program test 
   use bug1 
   implicit none 
   integer, target :: i 
   type(C_FUNPTR) p 
   p = C_FUNLOC(sub3) 
   call sub1(C_LOC(i)) 
   call sub2(C_FUNLOC(sub3)) ! Causes ICE 
   call sub2(p) ! No ICE 
end program test 

gives with trunk and 4.3.2:

pr34199_4.f90: In function 'test':
pr34199_4.f90:23: internal compiler error: in expand_expr_addr_expr_1, at expr.c:6848
Comment 8 Dominique d'Humieres 2008-09-06 19:14:47 UTC
Extracted from
http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/c553e0034bab977c
the following code

module bug1 
   use ISO_C_BINDING 
   implicit none 
   contains 
      subroutine sub1(x) 
         type(C_PTR) x 
         write(*,'(z16.16)') transfer(x,0_C_INTPTR_T) 
      end subroutine sub1 
      subroutine sub2(x) 
         type(C_FUNPTR) x 
         write(*,'(z16.16)') transfer(x,0_C_INTPTR_T) 
      end subroutine sub2 
end module bug1 
program test 
   use bug1 
   implicit none 
   call sub1(transfer(7_C_INTPTR_T,C_NULL_PTR)) 
   call sub2(transfer(7_C_INTPTR_T,C_NULL_FUNPTR)) 
end program test 

gives with trunk and 4.3.2

pr34199_3.f90:7: internal compiler error: Bus error
Please submit a full bug report,
Comment 9 Dominique d'Humieres 2008-09-06 21:16:17 UTC
Extracted from
http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/c553e0034bab977c
the following code

program bug2_transfer
   use ISO_C_BINDING
   implicit none
   type(C_PTR) C_NULL_PTR1

   C_NULL_PTR1 = transfer(23454_C_INTPTR_T, C_NULL_PTR1)
   write(*,'(a)') trim(merge('.TRUE. ','.FALSE.', &
      C_ASSOCIATED(C_NULL_PTR1)))
end program bug2_transfer

gives with trunk and 4.3.2

f951: internal compiler error: Bus error
Please submit a full bug report,
Comment 10 Dominique d'Humieres 2010-12-19 10:53:47 UTC
This PR seems to have been fixed at revision 168044 (likely r 168031).  May be pr46974 was a duplicate of this PR. Could someone check this and close this PR if it is the case? TIA
Comment 11 Tobias Burnus 2010-12-19 11:24:34 UTC
Yes, looks as duplicate of PR 46974.

*** This bug has been marked as a duplicate of bug 46974 ***