Bug 69298 - [OOP] Array finalisers seem to be given the wrong array when the array is a member variable
Summary: [OOP] Array finalisers seem to be given the wrong array when the array is a m...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 5.3.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks: Finalization
  Show dependency treegraph
 
Reported: 2016-01-15 14:20 UTC by matthew.hambley
Modified: 2019-03-27 17:06 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-01-24 00:00:00


Attachments
Minimal test case which exhibits problem (1.29 KB, application/x-bzip)
2016-01-15 14:20 UTC, matthew.hambley
Details
Self-contained variant (864 bytes, text/plain)
2016-01-24 15:15 UTC, Dominique d'Humieres
Details

Note You need to log in before you can comment on or make changes to this bug.
Description matthew.hambley 2016-01-15 14:20:37 UTC
Created attachment 37355 [details]
Minimal test case which exhibits problem

The attached example program exhibits the problem.

The basic situation is a type (stuff_type) and an array of that type which are initialised, some make-work is done and then they go out of scope so are finalised.

When this is done within a procedure within the program all works as expected.

When this is done within another type (test_type) the array finaliser does not behave as expected. The array passed to it (which should contain 3 stuff_type objects containing 1, 2 and 3) appears to contain objects only containing 1.

Compiling this example throws a lot of warnings about a missing scalar finaliser which is clearly not true. This is a known problem, see 58175.

This example behaves as expected when built using Intel Fortran.
Comment 1 Dominique d'Humieres 2016-01-24 14:58:48 UTC
I confirm a problem during the execution of the test:

thing 10
Finalising stuff_type 4

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

from 4.9 up to trunk (6.0), finalization being not implemented in 4.8.
Comment 2 Dominique d'Humieres 2016-01-24 15:15:38 UTC
Created attachment 37448 [details]
Self-contained variant
Comment 3 Dominique d'Humieres 2016-01-25 11:10:35 UTC
> Created attachment 37448 [details]
> Self-contained variant

With n=3, the output of the attached test is

Initialising stuff_type 4
Finalising stuff_type 0
...
---
Initialising test_type
Initialising stuff_type 4
Finalising stuff_type 0
Copy initialiser 4 4
Initialising stuff_type 1
Finalising stuff_type 0
Copy initialiser 1 1
Initialising stuff_type 2
Finalising stuff_type 0
Copy initialiser 2 2
Initialising stuff_type 3
Finalising stuff_type 0
Copy initialiser 3 3
Finalising stuff_type 4
Copy initialiser 4 4
thing 10
Finalising stuff_type 4

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

Changing 'n' to 2 or 4, gives respectively

...
---
Initialising test_type
Initialising stuff_type 4
Finalising stuff_type 1342972320
Copy initialiser 4 4
Initialising stuff_type 1
Finalising stuff_type 32767
Copy initialiser 1 1
Initialising stuff_type 2
Finalising stuff_type 263453344
Copy initialiser 2 2
Finalising stuff_type 4
Copy initialiser 4 4
thing 7
Finalising stuff_type 4

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

and

...
Initialising test_type
Initialising stuff_type 4
Finalising stuff_type 107478528
Copy initialiser 4 4
Initialising stuff_type 1
Finalising stuff_type 1
Copy initialiser 1 1
Initialising stuff_type 2
Finalising stuff_type 5120
Copy initialiser 2 2
Initialising stuff_type 3
Finalising stuff_type 0
Copy initialiser 3 3
Initialising stuff_type 4
Finalising stuff_type 1501114256
Copy initialiser 4 4
Finalising stuff_type 4
Copy initialiser 4 4
thing 14
Finalising stuff_type 4

where the nonzero values changed between different runs.
Comment 4 Paul Thomas 2016-10-24 19:16:11 UTC
(In reply to Dominique d'Humieres from comment #3)
> > Created attachment 37448 [details]
> > Self-contained variant
> 
> With n=3, the output of the attached test is
> 
> Initialising stuff_type 4
> Finalising stuff_type 0
> ...
> ---
> Initialising test_type
> Initialising stuff_type 4
> Finalising stuff_type 0
> Copy initialiser 4 4
> Initialising stuff_type 1
> Finalising stuff_type 0
> Copy initialiser 1 1
> Initialising stuff_type 2
> Finalising stuff_type 0
> Copy initialiser 2 2
> Initialising stuff_type 3
> Finalising stuff_type 0
> Copy initialiser 3 3
> Finalising stuff_type 4
> Copy initialiser 4 4
> thing 10
> Finalising stuff_type 4
> 
> Program received signal SIGSEGV: Segmentation fault - invalid memory
> reference.
> 
> Changing 'n' to 2 or 4, gives respectively
> 
> ...
> ---
> Initialising test_type
> Initialising stuff_type 4
> Finalising stuff_type 1342972320
> Copy initialiser 4 4
> Initialising stuff_type 1
> Finalising stuff_type 32767
> Copy initialiser 1 1
> Initialising stuff_type 2
> Finalising stuff_type 263453344
> Copy initialiser 2 2
> Finalising stuff_type 4
> Copy initialiser 4 4
> thing 7
> Finalising stuff_type 4
> 
> Program received signal SIGSEGV: Segmentation fault - invalid memory
> reference.
> 
> and
> 
> ...
> Initialising test_type
> Initialising stuff_type 4
> Finalising stuff_type 107478528
> Copy initialiser 4 4
> Initialising stuff_type 1
> Finalising stuff_type 1
> Copy initialiser 1 1
> Initialising stuff_type 2
> Finalising stuff_type 5120
> Copy initialiser 2 2
> Initialising stuff_type 3
> Finalising stuff_type 0
> Copy initialiser 3 3
> Initialising stuff_type 4
> Finalising stuff_type 1501114256
> Copy initialiser 4 4
> Finalising stuff_type 4
> Copy initialiser 4 4
> thing 14
> Finalising stuff_type 4
> 
> where the nonzero values changed between different runs.

For the record, since I have spent an hour or two investigating this tonight:

__final_test_mod_Test_type has, towards the end....


                {
                  struct array0_stuff_type desc.32;

                  desc.32.dtype = 296;
                  desc.32.data = (void * restrict) &ptr2->thing;
                  __final_stuff_mod_Stuff_type (&desc.32);
                }
                {
                  struct array1_stuff_type parm.33;

                  parm.33.dtype = 297;
                  parm.33.dim[0].lbound = 1;
                  parm.33.dim[0].ubound = 3;
                  parm.33.dim[0].stride = 1;
                  parm.33.data = (void *) &ptr2->things[0];
                  parm.33.offset = -1;
                  __final_stuff_mod_Stuff_type (&parm.33);
                }

whereas the prototype for the 'stuff' finalization is

__final_stuff_mod_Stuff_type (struct array7_stuff_type & restrict array, integer(kind=8) byte_stride, logical(kind=1) fini_coarray)


That is to say that two actual arguments are missing.

Since this contains
          if (byte_stride == 4)
            {
              {
                static integer(kind=8) C.3513 = 4;

                stuff_1d_finaliser ((struct array7_stuff_type *) array, &C.3513);
              }
            }

It seems difficult to understand how stuff_1d_finaliser is getting called at all!

I'll come back to this when I can.

Paul
Comment 5 Paul Thomas 2016-10-24 20:02:11 UTC
(In reply to Dominique d'Humieres from comment #3)
> > Created attachment 37448 [details]
> > Self-contained variant
> 
> With n=3, the output of the attached test is
> 
> Initialising stuff_type 4
> Finalising stuff_type 0
> ...
> ---
> Initialising test_type
> Initialising stuff_type 4
> Finalising stuff_type 0
> Copy initialiser 4 4
> Initialising stuff_type 1
> Finalising stuff_type 0
> Copy initialiser 1 1
> Initialising stuff_type 2
> Finalising stuff_type 0
> Copy initialiser 2 2
> Initialising stuff_type 3
> Finalising stuff_type 0
> Copy initialiser 3 3
> Finalising stuff_type 4
> Copy initialiser 4 4
> thing 10
> Finalising stuff_type 4
> 
> Program received signal SIGSEGV: Segmentation fault - invalid memory
> reference.
> 
> Changing 'n' to 2 or 4, gives respectively
> 
> ...
> ---
> Initialising test_type
> Initialising stuff_type 4
> Finalising stuff_type 1342972320
> Copy initialiser 4 4
> Initialising stuff_type 1
> Finalising stuff_type 32767
> Copy initialiser 1 1
> Initialising stuff_type 2
> Finalising stuff_type 263453344
> Copy initialiser 2 2
> Finalising stuff_type 4
> Copy initialiser 4 4
> thing 7
> Finalising stuff_type 4
> 
> Program received signal SIGSEGV: Segmentation fault - invalid memory
> reference.
> 
> and
> 
> ...
> Initialising test_type
> Initialising stuff_type 4
> Finalising stuff_type 107478528
> Copy initialiser 4 4
> Initialising stuff_type 1
> Finalising stuff_type 1
> Copy initialiser 1 1
> Initialising stuff_type 2
> Finalising stuff_type 5120
> Copy initialiser 2 2
> Initialising stuff_type 3
> Finalising stuff_type 0
> Copy initialiser 3 3
> Initialising stuff_type 4
> Finalising stuff_type 1501114256
> Copy initialiser 4 4
> Finalising stuff_type 4
> Copy initialiser 4 4
> thing 14
> Finalising stuff_type 4
> 
> where the nonzero values changed between different runs.

For the record, since I have spent an hour or two investigating this tonight:

__final_test_mod_Test_type has, towards the end....


                {
                  struct array0_stuff_type desc.32;

                  desc.32.dtype = 296;
                  desc.32.data = (void * restrict) &ptr2->thing;
                  __final_stuff_mod_Stuff_type (&desc.32);
                }
                {
                  struct array1_stuff_type parm.33;

                  parm.33.dtype = 297;
                  parm.33.dim[0].lbound = 1;
                  parm.33.dim[0].ubound = 3;
                  parm.33.dim[0].stride = 1;
                  parm.33.data = (void *) &ptr2->things[0];
                  parm.33.offset = -1;
                  __final_stuff_mod_Stuff_type (&parm.33);
                }

whereas the prototype for the 'stuff' finalization is

__final_stuff_mod_Stuff_type (struct array7_stuff_type & restrict array, integer(kind=8) byte_stride, logical(kind=1) fini_coarray)


That is to say that two actual arguments are missing.

Since this contains
          if (byte_stride == 4)
            {
              {
                static integer(kind=8) C.3513 = 4;

                stuff_1d_finaliser ((struct array7_stuff_type *) array, &C.3513);
              }
            }

It seems difficult to understand how stuff_1d_finaliser is getting called at all!

I'll come back to this when I can.

Paul
Comment 6 janus 2016-11-16 19:39:46 UTC
Here is a further reduced test case, based on Dominique's variant in comment #2, which (I think) runs into the same runtime-segfault when calling stuff_1d_finaliser ...



module stuff_mod

  implicit none

  type :: stuff_type
    integer :: junk
  contains
    final :: stuff_1d_finaliser
  end type

contains

  subroutine stuff_1d_finaliser( this )
    type(stuff_type), intent(inout) :: this(:)
    integer :: i
    write( 6, '("Finalising stuff_type array")', advance='no' )
    do i = lbound( this, 1 ), ubound( this, 1 )
      write(6, '(" ", I0)', advance='no' ) this(i)%junk
    end do
    write( 6, '()' )
  end subroutine

end module stuff_mod


program test

  use stuff_mod

  implicit none

  integer, parameter :: n = 2

  type test_type
    type(stuff_type) :: things(n)
  end type

  call sub()

contains

  subroutine sub()
    type(test_type) :: tt
    integer :: i
    write( 6, '("Initialising")' )
    do i = 1, n
      tt%things(i) = stuff_type( i )
    end do
    write( 6, '("Done")' )
  end subroutine

end
Comment 7 matthew.hambley 2018-11-20 08:27:01 UTC
A recent migration to RHEL7 seems to have exacerbated this issue.

Previously it could be worked around by ensuring that a type with user finaliser appeared before the array of finaliser types in the member variables list.

It seems that something has changed which means it is now no longer possible to work around it. The failure happens regardless of what other member variables exist.

I hope this additional information helps resolve this problem as it renders our unit tests (using pFUnit) non-functional with GCC.