Silverfrost Forums

Welcome to our forums

Shape of deallocated array

20 Apr 2023 12:42 #30209

In the following program, FTN95 remembers the shape of the allocatable array after it is deallocated. In other compilers the call to Shape generates a run-time error.

Program p
  Integer, Dimension(:), Allocatable :: i
  Allocate (i(2))
  Deallocate (i)
  Print*, Shape(i), Allocated(i)
End Program p

In my larger programme I am getting inconsistent behaviour when it is rerun with exactly the same inputs. I am wondering whether this problem is somehow related. Occasionally it seems that FTN95 returns an error when trying to reallocate this memory (I am using IOSTAT=, which returns 1), although I can confirm that allocated (i) is false before the call.

20 Apr 2023 6:11 #30210

Simon

I am not sure if I can provide any assistance on this issue but some details might depend on whether or not it is 64 or 32 bits, CHECK or not CHECK.

20 Apr 2023 6:33 #30211

Hi Paul,

I seem to get the same output ('2 F') regardless of which compiler options I use.

20 Apr 2023 11:44 #30212

Simon

I don't see how the problem could relate to the shape of an array after deallocate. FTN95 will allocate memory for a pointer to the allocated block and presumably for the returned shape. The pointer will be reset to NULL on deallocate but I guess that the shape won't be reset.

An IOSTAT value of 1 means that the resulting call to HeapAlloc has failed which in turn means that that there is insufficient memory or that the heap is corrupted. There is also the possibility that the requested size of the block of memory has got corrupted.

I presume that you have run tests using /CHECKMATE.

20 Apr 2023 3:12 #30213

Indeed, I have tried CHECKMATE. But forgetting about the larger programme for now, is Shape not returning an incorrect result even in the simple example? Size also returns 2 after i is deallocated.

21 Apr 2023 12:44 #30214

The 2008 (draft) standard explicitly states that the argument of both SHAPE and SIZE must not be an unallocated allocatable variable. So what a complier should or should not return in this case is not clearly defined.

21 Apr 2023 6:44 #30215

What FTN95 actually does after DEALLOCATE can be discovered by using /EXPLIST on the command line and decyphering the resultant listing but I don't think that it will have any bearing on the current problem.

Add some code locally to get the shape so that you can see how it relates to the registers and associated memory allocation.

21 Apr 2023 12:44 #30216

Line 5 of the short program in the first post has two function invocations in the output list, one of which is legal and the other is not. If we separate the two, as in

Program p
  Integer, Dimension(:), Allocatable :: i
  Allocate (i(2))
  Deallocate (i)
  Print*, Shape(i)      ! not legal, since i is not currently allocated
  Print *, Allocated(i) ! legal
End Program p

it is easier to discuss what the program may be expected to do, when it is compiled with and without /check.

When /check has not been used, the use of Shape(i) when the variable I is currently not allocated is incorrect, the program behaviour is undefined and it can do anything.

I think that when /check has been used the modified program should be able to detect the reference to Shape with an argument that is currently not allocated, issue an appropriate message, and abort execution. FTN95 currently does not do this, and a fix may be worth considering.

For this program, after compiling and linking with Lahey Fortran with the -Hx option, the program terminates with the output:

jwe0324i-w line 5 Allocatable array (i) is not allocated.
 error occurs at _MAIN__  line 5 loc 004010ce offset 000000ce
 _MAIN__      at loc 00401000 called from o.s.
29 Apr 2023 3:37 #30249

Many thanks to everyone's inputs. It has been helpful to know not to expect shape to 'work' (if that is the correct word) when its argument is deallocated.

I don't know whether this is a closely related problem, but in trying to trace the memory issues I referred to before, I encountered the following issue:

print *, shape(b),shape(a)
b(:,:) = a(:,:,1)
print *, shape(b)

a and b are both allocated, and in one example where this problem happens I get the following output:

35 36 35 36 1
1 36

I will see if I can create a small example of code to reproduce this problem ...

30 Apr 2023 11:44 #30251

If 'b' is deallocated, then I would expect shape(b) is undefined for values and also possibly for rank ?

For 'b(:,:) = a(:,:,1)' I am not sure if auto-allocate applies, although the following code example does not show this for both FTN95 and Gfortran.

I am unsure when auto-allocate does apply so I try to avoid this syntax.

Does the following code example help ? It does not reproduce your post result

! test of auto allocate
integer, allocatable :: a(:,:,:)
integer, allocatable :: b(:,:)
integer :: i,j,k

allocate ( a(4,7,3) )
allocate ( b(4,6) )

do k = 1,3
  do j = 1,7
    do i = 1,4
      a(i,j,k) = i+j+k
    end do
  end do
end do

  do j = 1,6
    do i = 1,4
      b(i,j) = i+j+4
    end do
  end do

print *, 'a', shape(a), size(a)
print *, 'b', shape(b), size(b)

b(:,:) = a(:,:,1)    !  not sure what happens here

print *, 'b', shape(b), size(b)
do j = 1,6
  write (*,*) j,b(:,j)
end do

end
30 Apr 2023 7:06 #30252

That would be interesting - if b were already allocated but got resized at the 'not sure what happens here' line, that could result in some very difficult to track problems.

1 May 2023 5:08 #30253

Here is an attempt to isolate the problem with the shape of an array being reassigned.

Module m1
   Implicit None
   Real, Dimension(:,:),   Allocatable, Public  :: b
   Real, Dimension(:,:,:), Allocatable, Public  :: a
End Module m1


Module m2
!
Contains
!
 Subroutine s1 ( )
   Use m1,           Only: a, b
!
   Call s2 ( )
   a = 1.0
   Print *, shape(a)
   Print *, shape(b)
   b(:,:) = a(:,:,1)
   Print *, shape(b)
!
   Return
 End Subroutine s1
!
!
 Subroutine s2 ( )
   Use m1, Only: a, b
!
   Allocate ( a(35,30,1) )
   Allocate ( b(35,30) )
!
   Return
 End Subroutine s2
End Module m2

It seems that the modules and main program may each need to be in a separate file:

Program p
   Use m2, Only: s1

   Call s1 ()
End Program p

But I am not entirely sure, because I do not get consistent results. If I keep everything in separate files, recompile and run, I get different outcomes. So far I have had the following outcomes:

  1. A run-time crash after the second print statement
  2. The program completes with no crash but the third print returns 1 30
  3. The third print returns 1 30 but a run-time error is issued

... but now that I have submitted this example, if I compile and run from a command prompt, it seems to work ok! But building it within a Plato project creates the error. I really hope somebody at Silverfrost can reproduce and diagnose the error. I can try to forward a simple package containing the relevant files and settings if that would be helpful.

2 May 2023 10:39 #30257

This appears to expose a bug in FTN95. A work-around is to have just one USE statement in module m2. Note that statements like 'b(:,:) = a(:,:,1)' might be very expensive. There could be a lot of work going on to evaluate the addresses for each copy.

Module m1
   Implicit None
   Real, Dimension(:,:),   Allocatable, Public  :: b
   Real, Dimension(:,:,:), Allocatable, Public  :: a
End Module m1


Module m2
Use m1, Only: a, b
!
Contains
!
 Subroutine s1 ( )
!
   Call s2 ( )
   a = 1.0
   Print *, shape(a)
   Print *, shape(b)
   b(:,:) = a(:,:,1)
   Print *, shape(b)
!
   Return
 End Subroutine s1
!
!
 Subroutine s2 ( )
!
   Allocate ( a(35,30,1) )
   Allocate ( b(35,30) )
!
   Return
 End Subroutine s2
End Module m2

program maim
use m2
call s1()
end program maim
2 May 2023 1:30 #30259

Thanks Paul. I'm relieved you were able to isolate the bug. It has taken a great deal of work to locate the problem and then produce the small example.

Are you able to be more generic about what we should avoid until this problem is resolved? I am concerned that this problem may be occurring elsewhere in my program undetected. Should we be avoiding a USE statement in more than one subroutine or function within a module, and if so, is that only for arrays? For arrays of more than one dimension? Only for arrays that are assigned values?

What would you suggest in place of the expensive line? Simply removing the brackets on the left? A DO CONCURRENT? I had programmed this section in that way specifically because I thought it permitted the most efficient code.

2 May 2023 6:50 #30260

Simon

I need to investigate this issue before I can give a clear reply. At the moment I am not sure that this exposes a bug in FTN95.

Since sub1 and sub2 share the same arrays A and B, it seems natural to me to USE (i.e. load) the module just once in the header rather than separately in each subprogram.

At the moment I am guessing that FTN95 is producing separate instances of A and B when when USE appears in both subroutines and that this is probably wrong according to the Standard.

2 May 2023 8:53 #30261

Understood Paul. Thanks for looking into this. I am loading a and b into the separate subprograms because typically the module contains a large number of subprograms, and I am looking to make available to each subprogram only those variables that it needs. If a and b are loaded before the CONTAINS statement, they become available to the every subprogram, which may not be desirable. Regardless, if s1 and s2 are in separate modules I get the same problem with the shape of b changing.

3 May 2023 6:44 #30262

Simon

The failure concerns 'allocate on assignment' (AOA) and the statement b(:,:) = a(:,:,1).

When using separate and local USE statements a work-around is to either 1) switch off /F2K which is on by default (add /-F2K) or 2) inhibit AOA with '/inhibit_F2K 1'.

At the moment I don't know if FTN95 should be attempting AOA in this context, nor why it fails.

The problem with AOA is that it has the potential to break existing code (or learned expectations) even when all related compiler bugs have been fixed. There might be a case for having AOA switched off by default with a separate option to switch it on. This would have an impact on users who have started to use AOA because it would stop working until the new switch is applied.

3 May 2023 10:02 #30263

Paul,

For the example I posted earlier in this thread, after 'b(:,:) = a(:,:,1)', both FTN95 and Gfortran report SHAPE(b) as [4,6] and not [4,7], which suggests to me that AOA is not being implemented in my example.

I am not familiar with AOA to be confident in this claim.

John

3 May 2023 11:26 #30267

John: Thanks for the feedback.

Simon: This failure has now been fixed for the next release of FTN95 (I can provide an new FTN95 straight away if needed).

When the array A is allocatable, its size is not known at compile time. With the fix, FTN95 will not attempt AOA in this context (i.e. that of the original reported failure).

3 May 2023 1:25 #30268

Hi Paul,

MANY thanks for your diligent work on this problem. Let me try the compiler switches and see what that effect is. If AOA has to be switched off, I can deal with that more easily than with this problem since I am only using AOA in a few cases. If I am still having difficulties I will get back to you about accessing the fix.

Given that b is already allocated, how come this is classified as an AOA issue?

Please login to reply.