Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29606 Discussions

Attempt to fetch from allocatable variable when it is not allocated

Alexis_R_
New Contributor I
4,231 Views
Dear all,

Using ifort 11.1.046 with -check all, I get "forrtl: severe (408): fort: (8): Attempt to fetch from allocatable variable VALUES when it is not allocated" at runtime, but I don't understand why. As far as I can tell, img1%values and img2%values are allocated. What am I doing wrong?


[cpp]module image_mod

	type image
		real, allocatable :: values(:)
	end type image

	interface assignment(=)
		module procedure image_assignment
	end interface

	interface operator(+)
		module procedure add_images
	end interface

	contains

		function add_images(img1,img2) result(imgout)
			implicit none
			type(image), intent(in) :: img1, img2
			type(image) :: imgout
			imgout%values = img1%values + img2%values
		end function

		subroutine image_assignment(imgout,imgin)
			implicit none
			type(image), intent(out) :: imgout
			type(image), intent(in)  :: imgin
			imgout%values = imgin%values
		end subroutine

end module image_mod

program images
	use image_mod
	implicit none

	type(image) :: img1, img2
	integer :: ierr

	allocate(img1%values(5), img2%values(5), stat=ierr)
	if (ierr == 0) write(*,*) 'Allocation successful'

	img1%values = 1.0
	img2%values = 2.0

	img2 = img1 + img2

	write(*,*) img2%values
end program images
[/cpp]
0 Kudos
12 Replies
TimP
Honored Contributor III
4,231 Views
0 Kudos
Kevin_D_Intel
Employee
4,231 Views

Compile with: -assume realloc_lhs

The thread (here) may be of interest/value too.
0 Kudos
Alexis_R_
New Contributor I
4,231 Views

Compile with: -assume realloc_lhs

The thread (here) may be of interest/value too.

Kevin,

Thanks for the hint. Using this option does remove the runtime error. However, it seems to me that this option is almost exactly the opposite of the behaviour I would want. I would much rather have a segfault if trying to write to an unallocated array or an array allocated the wrong size rather than duplicate or reallocate large arrays on the fly like the documentation for -assume realloc_lhs seems to imply:

Tells the compiler that when the left-hand side of an assignment is an allocatable object, it should be reallocated to the shape of the right-hand side of the assignment before the assignment occurs. This is the Fortran 2003 definition. This feature may cause extra overhead at run time.

(In fact, I don't really understand what this sentence means in detail. Is the entity on the left-hand side always reallocated, even when its shape already matches that of the right-hand side?)

Further, I feel there is an inconsistency at play. If I replace line 46 above with the line below, I don't have an error anymore at runtime.
[cpp]	img2%values = img1%values + img2%values[/cpp]
So the error I was getting ("Attempt to fetch from allocatable variable when it is not allocated") must have been plain wrong, since img1%values and img2%values can be read from and written to perfectly well with the line above. To my layman's eyes, this looks like buggy behaviour when checking the allocation status of allocatable arrays within derived types vs. allocatable arrays themselves.
0 Kudos
Alexis_R_
New Contributor I
4,231 Views
Quoting - tim18


Thanks for the link, my issue does seem related, in that it looks to me like in my case the checks for the allocation status of an array is dodgy when that array is within a derived type and isn't directly refered to in the assignment.
0 Kudos
Kevin_D_Intel
Employee
4,231 Views

Some details of the post Tim noted (reply #5 here) suggest a "SAVE imgout" may be needed in function add_images. Adding such a statement does not yield the desired results.

I'm still a bit unclear. The Doctor is in today so I will consult w/him.
0 Kudos
Alexis_R_
New Contributor I
4,231 Views

Some details of the post Tim noted (reply #5 here) suggest a "SAVE imgout" may be needed in function add_images. Adding such a statement does not yield the desired results.

I'm still a bit unclear. The Doctor is in today so I will consult w/him.

Thanks for looking into this.
0 Kudos
Steven_L_Intel1
Employee
4,231 Views
Kevin was correct in suggesting that you use -assume realloc_lhs. The issue is the assignment in image_assignment. The left side of this assignment is NOT allocated - the INTENT(OUT) guarantees that, even if the argument you passed to it was already allocated. If you change the INTENT to INOUT, then if the left side is already allocated to the proper shape, no reallocation will be done. However, if you can't guarantee this, then you'll have to deallocate it and then reallocate to the proper shape. Use of -assume realloc_lhs takes care of this.

You would not get the initial error ("Attempt to fetch...") unless you had also enabled "-check pointer". Perhaps you just have -check or -C.

So, my recommendation:

1. Use -assume realloc_lhs
2. Change the imgout argument to be INTENT(INOUT) to avoid unnecessary reallocation

P.S. SAVE is not appropriate or relevant to this discussion

0 Kudos
Steven_L_Intel1
Employee
4,231 Views
I forgot to mention. -assume realloc_lhs is absolutely required for the add_images routine since the result variable is initially unallocated.
0 Kudos
Alexis_R_
New Contributor I
4,231 Views
Thanks for your reply. It was foolish of me to overlook how using intent(out) on imgout would affect my problem.

I have a few remaining questions.
1. Is there no way to make sure that no reallocation happens under any circumstances? I would rather force the developer into making sure the lhs of the assignment is already allocated than allow on-the-fly reallocations.
2. Why is the option called -assume if it will only do it if the reallocation is necessary? Reading that part of the documentation again, I still feel it sounds like reallocation will happen every time, whether shapes match or not.
3. Why is -assume realloc_lhs absolutely necessary for add_images? On line 46 of the above example, the lhs of the assignment is allocated, therefore I would have thought IMGOUT in that instance of the assignment is allocated already. Are you saying that the allocation status of the function result is not checked at runtime?
3b. If the allocation status of the function result is not checked at runtime, does that mean that line 21 above creates a temporary array, the contents of which are then copied over to the lhs variable (imgout%values in this case)? If so, the operator overloading becomes useless for my purposes, since it would create huge overheads when dealing with huge arrays.


0 Kudos
Steven_L_Intel1
Employee
4,231 Views
1. If you don't use -assume realloc_lhs, then reallocation will not occur, except possibly for the line:

img2=img1+img2

but then, only if the shapes don't match. However, you'll then need to add an allocate in add_images because there's no way to "pass in" an already-allocated function result.

2. It's called "assume" because this is the name of the switch that tells the compiler what language behaviors should be in effect. There are quite a few other options. Most of these have to deal with reconciling traditional (or at least older) Intel/Compaq/DEC Fortran behavior with what newer standards specify. I note that at least one other Fortran vendor takes the same approach we do with "realloc_lhs" (they spell it differently). The reason for this option is that assignment of allocatable arrays in F90/95 required that the LHS already be allocated to the shape of the RHS and we felt that the extra checking code would slow down programs written to assume that. (Note that even if realloc_lhs is enabled, reallocation is done only if the shapes don't match or the LHS is not allocated.)

3. The LHS in the assignment is not part of the call to add_images. The right side of an assignment is completely evaluated before the left side is looked at. You could have img1+img2+img3+img4 , for example, which would cause add_images to be called three times. For each of these calls, the function result needs to go somewhere, and it goes into the newly allocated function result. If you don't add an explicit allocate to add_images. then you must use either realloc_lhs or get an error. An allocatable function result, like an INTENT(OUT) allocatable argument, starts out deallocated.

3b. Yes, it creates a temporary allocatable array which is automatically deallocated when the statement completes. The only alternative that comes to mind is to write a subroutine where you pass all three arguments, the LHS and the two RHS operands, and it has a DO loop that adds and assigns each element. No copy will be made in that case, but it is rather ugly in the code and not easily extensible.
0 Kudos
Alexis_R_
New Contributor I
4,231 Views
Steve,

Many thanks for the patient & clear explanation.

Question 1.

Quoting - Steve Lionel (Intel)
The right side of an assignment is completely evaluated before the left side is looked at.

Out of interest, what happens if I have something like this, where the assignment isn't within a function whose result is the LHS:
[cpp]REAL, ALLOCATABLE :: LARGEARRAY(:,:,:)
ALLOCATE(LARGEARRAY(1024,1024,1024))
LARGEARRAY = 1.0[/cpp]
Does the program (i) create a temporary array of shape (1024,1024,1024) filled with 1.0, and then copy contents over to LARGEARRAY and deallocate the temporary array, or (ii) directly write to LARGEARRAY, element-by-element? I always thought (ii), but I just want to make sure


Question 2.

Now that operator overloading does not seem to be an option for me, I'm going with a set of subroutines instead, e.g.
[cpp]	SUBROUTINE ADD_IMAGES(IMG1,IMG2,IMGOUT)
		IMPLICIT NONE
		TYPE(IMAGE), INTENT(IN)		::	IMG1
		TYPE(IMAGE), INTENT(IN)		::	IMG2
		TYPE(IMAGE), INTENT(INOUT)	::	IMGOUT

		IMGOUT%VALUES = IMG1%VALUES + IMG2%VALUES
	END SUBROUTINE ADD_IMAGES

[/cpp]
Am I correct in thinking that in this case, since the LHS is passed as an argument, (i) provided the three arrays have the same shapes, no reallocation of LHS will occur and (ii) the RHS is only evaluated one element at a time, creating a tiny overhead of one REAL (assuming just one thread / no optimisation)?


Again, thanks for the tuition :)
0 Kudos
Steven_L_Intel1
Employee
4,231 Views

1. Semantically, a temporary array is created, filled in and then copied. However, in this case, the optimizer recognizes that it doesn't need to do that and will very likely produce a nicely vectorized loop that does the initialization.

2. Again, semantically, a temporary is created and then copied. But again, this is the sort of assignment the compiler can optimize and you should get good code for this.
0 Kudos
Reply