Bug 54784 - [4.7/4.8 Regression] [OOP] wrong code in polymorphic allocation with SOURCE
[4.7/4.8 Regression] [OOP] wrong code in polymorphic allocation with SOURCE
Status: RESOLVED FIXED
Product: gcc
Classification: Unclassified
Component: fortran
4.8.0
: P3 normal
: ---
Assigned To: janus
: wrong-code
: 54874 (view as bug list)
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-10-02 20:07 UTC by Jeremy Kozdon
Modified: 2012-10-14 22:27 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-10-02 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jeremy Kozdon 2012-10-02 20:07:38 UTC
(Error also occurs with gcc 4.7.1)

When I have a container module with stores a collection of polymorphics types, I sometimes get an error that a pointer is being freed which was not allocated. 

An example program is below. It can be compiled without errors
   gfortran bug.f90

It contains four modules each with an associated type. If the type 'block' in 'block_module' the member nFields is commented out the code runs fine.

If a print statement is added in the program the code runs fine

If the dimension of the member 'x' of types block_cart1d and block_cart2d are changed so that they are not 3 and 4 (only one must be changed), the program works.

Finally, if the order in the program of the addBlock command is reversed the 

bug.f90
--------
module block_module
  implicit none
  private

  public :: block
  type,abstract :: block
    ! if commented out code works fine
    integer       ,private :: nFields      = 0
  end type block

end module block_module

module block1d_module
  use block_module, only : block

  type,extends(block) :: block1d
    real,dimension(:,:,:),allocatable,private :: fields
  end type
end module

module block2d_module
  use block_module, only : block

  type,extends(block) :: block2d
    real,dimension(:,:,:,:),allocatable,private :: fields
  end type
end module


module domain_module
  use block_module, only : block

  implicit none
  type :: list
    class(block),allocatable :: B
  end type

  type :: domain
    type(list),dimension(10) :: L
  contains
    procedure :: addBlock
  end type
contains

  subroutine addBlock(this,i,b)
    implicit none
    class(domain),intent(inout) :: this
    integer,intent(in) :: i
    class(block),intent(in) :: b

    allocate(this%L(i)%B,source=b)
  end subroutine
end module

program bug
  use domain_module, only : domain
  use block1d_module, only : block1d
  use block2d_module, only : block2d
  implicit none
  type(domain) :: d
  type(block1d) :: b1
  type(block2d) :: b2

  ! crashes with "pointer being freed was not allocated"
  call d%addBlock(1,b1)
  call d%addBlock(2,b2)

  ! crashes with "invalid memory reference"
  ! call d%addBlock(2,b2)
  ! call d%addBlock(1,b1)

  ! runs fine
  ! call d%addBlock(1,b2)
  ! call d%addBlock(2,b1)

end program  bug
Comment 1 janus 2012-10-02 21:51:49 UTC
Thanks for reporting this. I can reproduce it with 4.7 and trunk. Here is a reduced test case:

program bug
  implicit none

  type :: block
    real, allocatable :: fields
  end type

  type :: list
    class(block),allocatable :: B
  end type

  type :: domain
    type(list),dimension(2) :: L
  end type

  type(domain) :: d
  type(block) :: b1

  allocate(d%L(2)%B,source=b1)

end program  bug 



This fails at runtime with:

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

Backtrace for this error:
#0  0x7F379D1FDA97
#1  0x7F379D1FE074
#2  0x7F379C72ED9F
#3  0x400804 in __copy_bug_Block at bug.f90:9
#4  0x40097C in bug at bug.f90:19 (discriminator 2)
Segmentation fault


valgrind shows:

==11046== Invalid read of size 8
==11046==    at 0x400804: __copy_bug_Block (bug.f90:9)
==11046==    by 0x40097C: MAIN__ (bug.f90:19)
==11046==    by 0x400A88: main (bug.f90:21)
==11046==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
Comment 2 Jeremy Kozdon 2012-10-02 22:14:57 UTC
So there is actually two different bugs, one is the invalid memory reference which happens when you don't allocate in order.

There is a second, the one I was really trying to report, and that's when allocating in my original example type(block1d) before type(block2d), namely the call
  call d%addBlock(1,b1)
  call d%addBlock(2,b2)
as opposed to
  call d%addBlock(1,b2)
  call d%addBlock(2,b1)

This gives the error:
a.out(4678) malloc: *** error for object 0x7fff82ec09be: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

Program received signal SIGABRT: Process abort signal.

Backtrace for this error:
#0  0x100004fbe
#1  0x1000056d4
#2  0x7fff82f1f1b9
Abort trap

(In reply to comment #1)
> Thanks for reporting this. I can reproduce it with 4.7 and trunk. Here is a
> reduced test case:
> 
> program bug
>   implicit none
> 
>   type :: block
>     real, allocatable :: fields
>   end type
> 
>   type :: list
>     class(block),allocatable :: B
>   end type
> 
>   type :: domain
>     type(list),dimension(2) :: L
>   end type
> 
>   type(domain) :: d
>   type(block) :: b1
> 
>   allocate(d%L(2)%B,source=b1)
> 
> end program  bug 
> 
> 
> 
> This fails at runtime with:
> 
> Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
> 
> Backtrace for this error:
> #0  0x7F379D1FDA97
> #1  0x7F379D1FE074
> #2  0x7F379C72ED9F
> #3  0x400804 in __copy_bug_Block at bug.f90:9
> #4  0x40097C in bug at bug.f90:19 (discriminator 2)
> Segmentation fault
> 
> 
> valgrind shows:
> 
> ==11046== Invalid read of size 8
> ==11046==    at 0x400804: __copy_bug_Block (bug.f90:9)
> ==11046==    by 0x40097C: MAIN__ (bug.f90:19)
> ==11046==    by 0x400A88: main (bug.f90:21)
> ==11046==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
Comment 3 janus 2012-10-02 22:35:57 UTC
(In reply to comment #2)
> So there is actually two different bugs

Or the two different errors you are seeing are really due to the same underlying problem. I'm not quite sure about that yet, but I already have a suspicion ...


> one is the invalid memory reference
> which happens when you don't allocate in order.
> 
> There is a second, the one I was really trying to report, and that's when
> allocating in my original example type(block1d) before type(block2d), namely
> the call
>   call d%addBlock(1,b1)
>   call d%addBlock(2,b2)

Would be great if you could try to find a maximally reduced test for this case, too. That would definitely help a lot.

In the meantime, I will start looking at the case in comment 1 ...
Comment 4 janus 2012-10-02 22:45:31 UTC
(In reply to comment #1)
> 
>   allocate(d%L(2)%B,source=b1)
> 

The code generated for this line has two parts: The allocation and the copying from the source. While the first part looks fine, it seems there is a problem in the second. -fdump-tree-original shows:

      {
        struct block D.1890;
        struct list[2] * D.1889;

        D.1889 = &d.l;
        D.1890 = b1;
        {
          integer(kind=8) S.0;

          S.0 = 1;
          while (1)
            {
              if (S.0 > 2) goto L.1;
              __vtab_bug_Block._copy (&D.1890, (*D.1889)[S.0 + -1].b._data);
              S.0 = S.0 + 1;
            }
          L.1:;
        }
      }

In principle only one element of the array 'd.l' should be copied. However, it seems like the while loop does a copy for each element!
Comment 5 janus 2012-10-02 23:43:42 UTC
The following patch seems to cure the test case in comment 1, as well as both variants in comment 0:


Index: gcc/fortran/trans-stmt.c
===================================================================
--- gcc/fortran/trans-stmt.c	(revision 192004)
+++ gcc/fortran/trans-stmt.c	(working copy)
@@ -5145,7 +5145,9 @@ gfc_trans_allocate (gfc_code * code)
 	      dataref = actual->next->expr->ref;
 	      /* Make sure we go up through the reference chain to
 		 the _data reference, where the arrayspec is found.  */
-	      while (dataref->next && dataref->next->type != REF_ARRAY)
+	      while (!(dataref->type == REF_COMPONENT
+		       && strcmp (dataref->u.c.component->name, "_data") == 0)
+		     && dataref->next)
 		dataref = dataref->next;
 
 	      if (dataref->u.c.component->as)
Comment 6 janus 2012-10-03 10:38:22 UTC
(In reply to comment #5)
> The following patch seems to cure the test case in comment 1, as well as both
> variants in comment 0:

... and regtests cleanly!
Comment 7 janus 2012-10-03 16:09:03 UTC
This even seems to be a regression: The test case in comment 1 runs without error when compiled with gfortran 4.6 (and also the dump looks ok).
Comment 8 Salvatore Filippone 2012-10-08 16:22:42 UTC
Hello,
I have a different problem that is definitely related to this area, but may or may not be the same. 
I have (as usual :) a complex nesting of polymorphic derived types, and I have a need to handle reallocation and re-population of a vector of such containers. 
The type hierarchy is something like this

  type mld_d_base_solver_type
  end type 

  type  mld_d_base_smoother_type
    class(mld_d_base_solver_type), allocatable :: sv
  end 

  type mld_d_onelev_type
    class(mld_d_base_smoother_type), allocatable :: sm
  end type 

  type, extends(psb_dprec_type)         :: mld_dprec_type
    type(mld_d_onelev_type), allocatable :: precv(:) 
  end type 


Consider the following snippet of code:
  --------------------
    deallocate(p%precv,stat=info)

    if (info == 0) allocate(p%precv(newsz),stat=info) 
    if (info /= 0) then 
      info = -1
      return
    end if

    do i=1, newsz
      if (info == 0) then 
        if (i ==1) then 
          allocate(p%precv(i)%sm,source=base_sm,stat=info) 
        else if (i < newsz) then 
          allocate(p%precv(i)%sm,source=med_sm,stat=info) 
        else
          allocate(p%precv(i)%sm,source=coarse_sm,stat=info) 
        end if
      end if
      if (info /= 0) then 
        info = -1
        return
      end if
      write(0,*) 'Copy back at level',i
      do k=1,i
        write(0,*) '   level',k
        call p%precv(k)%sm%sv%descr(info,iout=0)
        if (info /= 0) return
      end do



    end do
------------------------------------------------
You would expect the allocate with source at I=4 to leave untouched the elements of p%precv(1:3), and yet this is the output I get with 4.7.2:
------------------------------------------------
   
 Copy back at level           1
    level           1
   TLU: test a new solver kind
   
 Copy back at level           2
    level           1
   TLU: test a new solver kind
   
    level           2
   TLU: test a new solver kind
   
 Copy back at level           3
    level           1
   TLU: test a new solver kind
   
    level           2
   TLU: test a new solver kind
   
    level           3
   TLU: test a new solver kind
   
 Copy back at level           4
    level           1
   Incomplete factorization solver: ILU(n)         
   Fill level:           0
    level           2
   Incomplete factorization solver: ILU(n)         
   Fill level:           0
    level           3
   Incomplete factorization solver: ILU(n)         
   Fill level:           0
    level           4
   Incomplete factorization solver: ILU(n)         
   Fill level:           0
 Intermediate at level 1
   Incomplete factorization solver: ILU(n)         
   Fill level:           0
-----------------------------------------------------------------
This clearly does not make sense. 
I can send Janus the full code to reproduce the error. 
Does it seem related? 
Thanks
Salvatore
Comment 9 Salvatore Filippone 2012-10-09 09:59:28 UTC
Just opened 54874. May or may not be a duplicate of this one.....
Comment 10 janus 2012-10-10 11:49:02 UTC
*** Bug 54874 has been marked as a duplicate of this bug. ***
Comment 11 janus 2012-10-11 17:52:44 UTC
Author: janus
Date: Thu Oct 11 17:52:36 2012
New Revision: 192374

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=192374
Log:
2012-10-11  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/54784
	* trans-stmt.c (gfc_trans_allocate): Correctly determine the reference
	to the _data component for polymorphic allocation with SOURCE.

2012-10-11  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/54784
	* gfortran.dg/class_allocate_13.f90: New.

Added:
    trunk/gcc/testsuite/gfortran.dg/class_allocate_13.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/trans-stmt.c
    trunk/gcc/testsuite/ChangeLog
Comment 12 janus 2012-10-11 17:58:19 UTC
r192374 fixes the problem on trunk. Will commit to the 4.7 branch soon.
Comment 13 janus 2012-10-14 22:16:29 UTC
Author: janus
Date: Sun Oct 14 22:16:24 2012
New Revision: 192442

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=192442
Log:
2012-10-14  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/54784
	* trans-stmt.c (gfc_trans_allocate): Correctly determine the reference
	to the _data component for polymorphic allocation with SOURCE.

2012-10-14  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/54784
	* gfortran.dg/class_allocate_13.f90: New.

Added:
    branches/gcc-4_7-branch/gcc/testsuite/gfortran.dg/class_allocate_13.f90
Modified:
    branches/gcc-4_7-branch/gcc/fortran/ChangeLog
    branches/gcc-4_7-branch/gcc/fortran/trans-stmt.c
    branches/gcc-4_7-branch/gcc/testsuite/ChangeLog
Comment 14 janus 2012-10-14 22:27:12 UTC
Fixed for the upcoming releases 4.8.0 and 4.7.3. Closing.

Thanks again for the report!