Silverfrost Forums

Welcome to our forums

Bug with pointer components of derived type.

16 Feb 2013 9:06 (Edited: 17 Feb 2013 8:08) #11572

The following code contains a derive type PER_T which contains a pointer to an array of derived type GRP_T.

The derived type GRP_T in turn contains a pointer to an array of derived type EL_T.

When the line marked (A) is executed, the members of pers(1) lose their values and are set to zero. The allocate on this line is not working; this is indicated by the pointer in line (B) which becomes NULL.

I have tracked this down to be due to the use of null() to initialise the els(:) pointer in line (C). If I remove this initialisation, the code works correctly.

Please can this be fixed?

Regards David

program anon

   type el_t
      real :: a
   end type el_t

   type grp_t
      type(el_t), pointer :: els(:) => null()  ! (C)
   end type grp_t

   type per_t
      integer :: num
      real :: x
      type(grp_t), pointer :: grps(:) => null()
   end type per_t

   type(per_t), allocatable :: pers(:)

   integer :: i
   type(grp_t), pointer :: grps_ptr(:)

   allocate (pers(1))

   ! Setup values of pers(1)
   pers(1)%num = 1
   pers(1)%x = 1.0

   ! Allocate grps(:) part of pers(1) to point to array of size 5
   allocate(pers(1)%grps(5))          !< (A) BUG HERE. Value of pers(1)%num and pers(1)%x get changed to 0
   grps_ptr => pers(1)%grps(:)        !< (B) BUG HERE. grps_ptr is NULL POINTER and shouldn't be

   ! Allocate els(:) to point to array of size 1
   do i=1, 5
      allocate (pers(1)%grps(i)%els(1))
   end do

   ! Set value of a in els
   pers(1)%grps(1)%els(1)%a = 2.0

   print *, pers(1)%num
   print *, pers(1)%x

end program anon
17 Feb 2013 8:20 #11573

Thanks. I have logged this for investigation.

31 Jul 2013 7:10 #12717

This is still an issue with 6.35. I wonder if it could be patched for the next release please.

I have produced the following very simple example to show what is wrong. When the second allocate is done, the data at the address of per(1) is initialized instead of the data at address of grps(1) (corrupting the value of num).

The error is also obvious from the EXPLIST for this code.

program anon

   type grp_t
      integer :: n = 2 ! (C)
   end type grp_t

   type per_t
      integer :: num
      type(grp_t), pointer :: grps(:) => null()
   end type per_t

   type(per_t), allocatable :: pers(:)

   ! Setup values of pers(1)
   allocate (pers(1))   
   pers(1)%num = 1

   ! BUG HERE. Allocate needs to set n = 2 to initialise grps(1).
   ! However the data at the address of pers(1) is initialised instead.
   ! This causes the value of pers(1)%num to change to 2

   ! Allocate grps(:) part of pers(1) to point to array of size 1   
   allocate(pers(1)%grps(1))

   print *, pers(1)%num, ' <-- should be 1 !'

end program anon
2 Aug 2013 6:47 #12735

I did do a preliminary investigation on this bug, sufficient to indicate that it is a reality nasty one to fix.

Given that a new release is planned shortly, it is unlikely that this one can be fixed in time.

2 Aug 2013 7:12 #12738

If you can get the front end of the compiler to replace

allocate(pers(1)%grps(1))

by

p => pers(1)
allocate(p%grps(1))

the BUG will disappear.

I can do this in Fortran code, but have to declare pers with the TARGET attribute, which I don't really need.

I am surprised this is so tricky. Looks like just an address is wrong looking at the assembly.

2 Aug 2013 7:28 #12739

Thanks for the suggestion.

12 Apr 2014 1:05 #13959

Paul,

Was this bug fixed as a side-effect of the recent fix to default initialisation in the next release, or is it still an ongoing issue.

14 Apr 2014 6:49 #13960

Unfortunately this issue is still outstanding.

26 Apr 2014 9:27 #14002

I have been studying this some more and have found the problem (at least at the assembly level).

I looked at the following codes, which are the simplest I can make which reproduces the problem.

Code P1 shows the BUG and doesn't work, while P2 works fine. The only difference is that the integer x is located at the start of bbb in code P1, whereas in P2 the pointer array is at the beginning.

! Doesn't work
program P1

    type aaa_t
       integer :: a = 999
    end type aaa_t 

    type bbb_t
       integer :: x 
       type(aaa_t), pointer :: aaa(:)
    end type bbb_t 

    type(bbb_t) :: bbb(1) 

    ! Setup bbb(1) 
    bbb(1)%x = 1 

    ! Allocate aaa(:) part of bbb(1) to point to array of size 5
    allocate(bbb(1)%aaa(5)) 
    
    print *, bbb(1)%x, ' <= should be 1 but 999 is printed!'

 end program P1



! Works
program P2

    type aaa_t
       integer :: a = 999
    end type aaa_t 

    type bbb_t
       type(aaa_t), pointer :: aaa(:)
       integer :: x   
    end type bbb_t 

    type(bbb_t) :: bbb(1) 

    ! Setup bbb(1) 
    bbb(1)%x = 1 

    ! Allocate aaa(:) part of bbb(1) to point to array of size 5
    allocate(bbb(1)%aaa(5)) 
    
    print *, bbb(1)%x, ' <= should be 1 and is!'

 end program P2

The assembly code for P1 and P2 include the following loop for doing the default initialisation (its the same assembly code in each case):

      00000090(42/3/458)      Label     __N3
      00000090(43/6/492)         mov       ecx,II@01
      00000093(44/6/492)         imul      ecx,=28
      00000099(45/4/289)         mov       edx,AAA_T(999)
      0000009f(46/4/289)         mov       BBB[ecx],edx
      000000a3(47/4/467)         inc       II@01
      000000a6(48/4/468)         mov       eax,LoopUpper@1
      000000a9(49/4/468)         cmp       eax,II@01
      000000ac(50/4/468)         jge       __N3

II@01 is the loop counter which starts at 0 and LoopUpper@1 is upper value of the loop counter, 4.

In this code register ecx used in BBB[ecx] contains the successive values 0, 28, 56, etc. This is correct for P2. However it isn't correct for P1 where it needs to contain the values 4, 32, 60, etc.

You could possibly fix this by adding the appropriate offset to ecx as follows.

      00000090(43/6/492)         mov       ecx,II@01
      00000093(44/6/492)         imul      ecx,=28
                                 add       ecx, 4

Obviously the offset to be added will change depending on where in BBB the pointer array is located. In code P2 for example, the offset would be zero (which explains why the BUG doesn't get exposed in this case).

PS. I also looked at the equivalent of P1 but with a scalar for BBB instead of an array of size 1; this code works and has the offset that is needed.

      00000090(42/3/267)      Label     __N3
      00000090(43/6/278)         mov       ecx,BBB[8]
      00000093(44/6/278)         add       ecx,II@01
      00000096(45/5/280)         mov       edi,BBB[4]
      00000099(46/4/159)         mov       eax,AAA_T(999)
      0000009f(47/4/159)         mov       [edi+ecx*4],eax
      000000a3(48/4/274)         inc       II@01
      000000a6(49/4/275)         mov       ecx,LoopUpper@1
      000000a9(50/4/275)         cmp       ecx,II@01
      000000ac(51/4/275)         jge       __N3

I hope this helps

26 Apr 2014 3:04 #14008

Thanks for this. I will make a note of your analysis.

However, this needs to be fixed in the tree structure before we get to the backend assembly. That way the fix is applied to both Win32 and .NET and potentially Win64. The backend will handle it once the tree is fixed.

26 Apr 2014 5:05 #14011

Yes, it needs fixing in the front end.

As FTN95 doesn't expose the abstract tree I haven't been able to look at it.

But hopefully having this little look at the assembly code for Win32 may provide some insight into what may be going on. You at least know that an incorrect memory offset is the cause. You might also look at the difference between the abstract tree for the cases where BBB is an array (which fails) and where BBB is a scalar (which works).

Good luck and thanks for looking Paul. Default initialisation does seem to be a big feature in my coding at present (like a habit), and I am having to do explicit initialisation as a workaround with FTN95.

26 Apr 2014 5:09 #14012

Quoted from PaulLaidler and potentially Win64.

Are you teasing us?

27 Apr 2014 5:48 #14013

Wow...64bit... please don't say NO, Paul

24 Jun 2019 9:47 #23842

This issue has finally been fixed. The fix will be in the next release of FTN95.

7 Jul 2019 5:05 #23932

Thanks Paul, your work on this is much appreciated.

Please login to reply.