Bug 44912 - [OOP] Segmentation fault on TBP
[OOP] Segmentation fault on TBP
Status: RESOLVED FIXED
Product: gcc
Classification: Unclassified
Component: fortran
4.6.0
: P3 normal
: ---
Assigned To: janus
: wrong-code
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2010-07-11 17:03 UTC by Satish.BD
Modified: 2010-08-01 19:24 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-07-31 11:35:13


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Satish.BD 2010-07-11 17:03:15 UTC
Reported by Satish.BD at http://gcc.gnu.org/ml/fortran/2010-07/msg00109.html

The shown (cf. URL) program compiles without any errors, but segfaults at
run time.

It seems that the call to 'get_coefficients' is what produces the segfault.
Comment 1 janus 2010-07-29 19:36:06 UTC
Here is a reduced/modified version of the code in comment #0, which also exhibits a runtime segfault, although the code seems to be valid:


module polynomial
implicit none

private

type, public :: polynom
   complex, allocatable, dimension(:) :: a
   integer :: n
 contains
   procedure :: init_from_coeff
   procedure :: get_degree
   procedure :: add_poly
end type polynom

contains
  subroutine init_from_coeff(self, coeff)
    class(polynom), intent(inout) :: self
    complex, dimension(:), intent(in) :: coeff
    self%n = size(coeff) - 1
    allocate(self%a(self%n + 1))
    self%a = coeff
    print *,"ifc:",self%a
  end subroutine init_from_coeff

  function get_degree(self)   result(n)
    class(polynom), intent(in) :: self
    integer :: n
    print *,"gd"
    n = self%n
  end function get_degree

  subroutine add_poly(self)
    class(polynom), intent(in) :: self
    integer :: s
    print *,"ap"
    s = self%get_degree()         !!!! fails here
  end subroutine

end module polynomial

program test_poly
   use polynomial

   type(polynom) :: p1

   call p1%init_from_coeff([(1,0),(2,0),(3,0)])
   call p1%add_poly()

end program test_poly


After being compiled with gfortran r162688 on x86_64-unknown-linux-gnu, it prints the following output:

 ifc: (  1.0000000    ,  0.0000000    ) (  2.0000000    ,  0.0000000    ) (  3.0000000    ,  0.0000000    )
 ap
Segmentation fault


Valgrind says:

==25251== Invalid read of size 8
==25251==    at 0x400A02: __polynomial_MOD_init_from_coeff (c0.f90:42)
==25251==    by 0x400950: __polynomial_MOD_add_poly (c0.f90:36)
==25251==    by 0x400DCF: MAIN__ (c0.f90:47)
==25251==    by 0x400E30: main (c0.f90:42)
==25251==  Address 0x1c is not stack'd, malloc'd or (recently) free'd
==25251== 
==25251== 
==25251== Process terminating with default action of signal 11 (SIGSEGV)
==25251==  Access not within mapped region at address 0x1C
==25251==    at 0x400A02: __polynomial_MOD_init_from_coeff (c0.f90:42)
==25251==    by 0x400950: __polynomial_MOD_add_poly (c0.f90:36)
==25251==    by 0x400DCF: MAIN__ (c0.f90:47)
==25251==    by 0x400E30: main (c0.f90:42)


This is a very strange error. It seems "init_from_coeff" is called from "add_poly", although this is definitely not the case in the Fortran code. Maybe something goes wrong in the vtab, like PPCs having wrong addresses, etc.
Comment 2 Tobias Burnus 2010-07-29 21:13:07 UTC
(In reply to comment #1)
> Here is a reduced/modified version of the code in comment #0, which also
> exhibits a runtime segfault, although the code seems to be valid:
[...]
> it prints the following output:
>  ifc: (  1.0000000    ,  0.0000000    ) (  2.0000000    ,  0.0000000    ) ( 
> 3.0000000    ,  0.0000000    )
>  ap
> Segmentation fault

For completeness: With NAG f95 v5.1, ifort, and crayftn it prints:

 ifc: (1.,0.),  (2.,0.),  (3.,0.)
 ap
 gd
Comment 3 Tobias Burnus 2010-07-30 07:02:23 UTC
(In reply to comment #2)
> > it prints the following output:
> >  ifc: (  1.0000000    ,  0.0000000    ) (  2.0000000    ,  0.0000000    ) ( 
> > 3.0000000    ,  0.0000000    )
> >  ap
> > Segmentation fault

If one changes the order of PROCEDURE statements, one can also call "add_poly" recursively. The dump by itself looks OK, but I was puzzled by:

  vtab$polynom.get_degree = get_degree;
  vtab$polynom.add_poly = add_poly;
  vtab$polynom.init_from_coeff = (void (*<T4cc>) (struct class$polynom & restrict, struct array1_complex(kind=4) & restrict)) init_from_coeff;

Why is there a cast for init_from_coeff?

Thinking about it a bit more: My vague feeling is that the backend_decl for the module procedure "init_from_coeff" is not used in the assignment but some external "init_from_coeff" (with the same assembler name) or something like that. The reason for that could be that the decl is not quite available as the procedures are marked as PRIVATE. -- It works without the PRIVATE and it works if one splits the module and the PROGRAM into two separate files.

You could check in (gfc_get_symbol_decl,) gfc_get_extern_function_decl, and gfc_create_function_decl whether the sym->backend_decl for "init_from_coeff" is always the same - or whether a new, non-gsym(bol) decl is generated in gfc_get_extern_function_decl.
Comment 4 Tobias Burnus 2010-07-30 15:29:55 UTC
One observation: In case one does not have PRIVATE, one initializes seemingly the global variable
   __polynomial_MOD_vtab
while with PRIVATE and failing, one uses the variables vtab$polynomD which is local in "test_poly"; admittedly, I do not fully understand the code which sets the TBP to the vtable - shouldn't this be done when the vtable for a type is created rather than every time before it is used? Or couldn't this be done before because there was no -fwhole-file? For types defined in modules, this information should be available after the module procedures have been generated.
Comment 5 janus 2010-07-30 18:39:23 UTC
(In reply to comment #4)
> admittedly, I do not fully understand the code which sets
> the TBP to the vtable - shouldn't this be done when the vtable for a type is
> created rather than every time before it is used?

Well, this is a bit tricky. We do not want to generate unnecessary code for non-OOP programs, therefore we can not simply create a vtab for each derived type, but we only do that if a type is actually used as a CLASS.

Another problem is that the vtab init code can be generated multiple times if there are multiple CLASS usage cases in a program (blowing up code size). It might be of advantage to put the vtab init code in a special subroutine. [Preferrably in the same module where the type is declared, but this only makes sense if the module contains polymorphic code.]
Comment 6 janus 2010-07-30 18:46:11 UTC
(In reply to comment #4)
> One observation: In case one does not have PRIVATE, one initializes seemingly
> the global variable
>    __polynomial_MOD_vtab
> while with PRIVATE and failing, one uses the variables vtab$polynomD which is
> local in "test_poly";

Good point. Actually the test case is fixed by making the vtab public:

Index: gcc/fortran/class.c
===================================================================
--- gcc/fortran/class.c (revision 162723)
+++ gcc/fortran/class.c (working copy)
@@ -343,6 +344,7 @@
          vtab->attr.target = 1;
          vtab->attr.save = SAVE_EXPLICIT;
          vtab->attr.vtab = 1;
+         vtab->attr.access = ACCESS_PUBLIC;
          vtab->refs++;
          gfc_set_sym_referenced (vtab);
          sprintf (name, "vtype$%s", derived->name);
@@ -357,6 +359,7 @@
              if (gfc_add_flavor (&vtype->attr, FL_DERIVED,
                                  NULL, &gfc_current_locus) == FAILURE)
                goto cleanup;
+             vtype->attr.access = ACCESS_PUBLIC;
              vtype->refs++;
              gfc_set_sym_referenced (vtype);
Comment 7 janus 2010-07-30 18:54:12 UTC
(In reply to comment #6)
> Good point. Actually the test case is fixed by making the vtab public:

Of course this does not fix the actual problem, but it limits the set of affected cases (and I guess it's a good idea in general).

The test case still fails when adding an 'only' clause in the use statement:

   use polynomial, only: polynom

Comment 8 janus 2010-07-30 20:56:35 UTC
(In reply to comment #7)
> The test case still fails when adding an 'only' clause in the use statement:
> 
>    use polynomial, only: polynom
> 

This case can be fixed by the following patchlet:

Index: module.c
===================================================================
--- module.c    (revision 162723)
+++ module.c    (working copy)
@@ -4370,6 +4370,11 @@
          if (p == NULL && strcmp (name, module_name) == 0)
            p = name;
 
+         /* Exception: Always import vtabs & vtypes.  */
+         if (p == NULL && (strcmp (strndup (name,5), "vtab$") == 0
+                           || strcmp (strndup (name,6), "vtype$") == 0))
+           p = name;
+
          /* Skip symtree nodes not in an ONLY clause, unless there
             is an existing symtree loaded from another USE statement.  */
          if (p == NULL)
Comment 9 janus 2010-08-01 19:22:03 UTC
Subject: Bug 44912

Author: janus
Date: Sun Aug  1 19:21:49 2010
New Revision: 162804

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=162804
Log:
2010-08-01  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/44912
	* class.c (gfc_build_class_symbol): Make '$vptr' component private.
	(gfc_find_derived_vtab): Make vtabs and vtypes public.
	* module.c (read_module): When reading module files, always import
	vtab and vtype symbols.

2010-08-01  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/44912
	* gfortran.dg/typebound_call_17.f03: New.

Added:
    trunk/gcc/testsuite/gfortran.dg/typebound_call_17.f03
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/class.c
    trunk/gcc/fortran/module.c
    trunk/gcc/testsuite/ChangeLog

Comment 10 janus 2010-08-01 19:24:25 UTC
Fixed with r162804. Closing.