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

Deallocation issues

Dino_R_
Beginner
431 Views

Hi,

I've come to notice a very strange behaviour with the intel compiler on Linux. It's a bit difficult to explain, since I'm not able to make a minimal example (for reasons which will become apparent). What I'm doing is basically calling a set of subroutines which kind of look like that:

SUBROUTINE WHATEVER (a, b, table)
   IMPLICIT NONE
   DOUBLE PRECISION, POINTER, DIMENSION(:), INTENT(IN) :: a
   DOUBLE PRECISION, POINTER, DIMENSION(:), INTENT(IN) :: b
   DOUBLE PRECISION, POINTER, DIMENSION(:,:,:,:), INTENT(OUT) :: table

   ALLOCATE(table( ... ) )
   table= ...

END SUBROUTINE WHATEVER

I have 6 of such routines which all allocate and define multidimensional arrays of up to six dimensions. Now, before I started implementing calculations with those tables I just tried to set them up and deallocate them to see if the compiler complains:

SUBROUTINE SOMETHING (a,b)
   DOUBLE PRECISION, POINTER, DIMENSION(:), INTENT(IN) :: a
   DOUBLE PRECISION, POINTER, DIMENSION(:), INTENT(IN) :: b

   DOUBLE PRECISION, POINTER, DIMENSION(:,:,:,:) :: table_a
   DOUBLE PRECISION, POINTER, DIMENSION(:,:,:,:) :: table_b
   DOUBLE PRECISION, POINTER, DIMENSION(:,:,:,:) :: table_c
   DOUBLE PRECISION, POINTER, DIMENSION(:,:,:,:) :: table_d
   DOUBLE PRECISION, POINTER, DIMENSION(:,:,:,:,:,:) :: table_e

   CALL WHATEVER_a (a, b, table_a)
   CALL WHATEVER_b (a, b, table_b)
   CALL WHATEVER_c (a, b, table_c)
   CALL WHATEVER_d (a, b, table_d)
   CALL WHATEVER_e (a, b, table_e)
   CALL WHATEVER_f (a, b, table_f)

   DEALLOCATE(table_a, table_b, table_c, table_d, table_e, table_f)


   !Do something TOTALLY UNRELATED to those arrays
   .......

END SUBROUTINE SOMETHING

My program compiled without issues.  But during runtime I get an inconsistent result (I have my own routines that check for any unexpected results).  There is no runtime error, it's just that something has changed in another calculation in an entirely unrelated subroutine. And that's the point which confuses me the most: The other subroutine which suffers a weird change in it's values has nothing in common with the subroutine where I allocate and deallocate the arrays. I mean, seriously, nothing. No Module, no arguments,  nothing. If I remove the DEALLOCATE statement, it works just fine, also if I deallocate only one of those arrays, everything is fine...

It appears something is wrong with the deallocation. When I move the deallocation into the WHATEVER_x subroutines, everything is ok as  well.

Since I don't have any particular knowledge about the inner workings of the compiler or how the DEALLOCATE statement is implemented, I'm kind of left with a questionmark hovering above my head. But if I'd have to guess, I'd say that the results of anything shouldn't depend on whether I deallocate at the end of a subroutine or immediately after the return to the main routine. Also, it should be entirely impossible for two completely disjoint routines to have side-effects on each other. Except that the deallocation statement messes something up in the memory...

Am I doing something wrong here? Any suggestions how I could test what's going on?


Thanks
Dino

0 Kudos
8 Replies
TimP
Honored Contributor III
431 Views

It looks like the arrays are deallocated implicitly when exiting the procedure where they are allocated, as they should be.  The automatic deallocation started with f95.

0 Kudos
Dino_R_
Beginner
431 Views

Thanks for the quick reply.

Maybe I'm not understanding this correctly... The arrays are available outside of the subroutine where they're allocated, so there is no deallocation happening within the routine. Also, deallocation of an already deallocated pointer (usually) throws exceptions, which is not the case. The issue also occurs if I allocate outside of the WHATEVER_x routine and deallocate right after (basically doing nothing). The point being: If I write down the deallocate statement for the arrays, I will effectively change the result of an unrelated routine somewhere else in the program.

0 Kudos
mecej4
Honored Contributor III
431 Views

The lines

[fortran]   ALLOCATE(table( ... ) )
   table= ...

[/fortran] had me asking if you ever checked for success in allocating before assigning values to the variable for which allocation was attempted. Depending on whether pointers are checked for association before values are assigned to the corresponding variable, behavior of the sort that you described could occur.

0 Kudos
IanH
Honored Contributor II
431 Views

Do the subroutines WHATEVER_* and SOMETHING have explicit interfaces (are they module procedures, internal procedures or is an INTERFACE block for the subroutine accessible)?

0 Kudos
Dino_R_
Beginner
431 Views

I do not check ALLOCATED or ASSOCIATED status in those particular routines.

The WHATEVER_* are part of the same MODULE where they are called, so no explicit interface is required.

I will try to check for the status of those arrays before and after I use them. I should've done that anyway. I'll report back if I find something. Thanks for the suggestion.

0 Kudos
Dino_R_
Beginner
431 Views

I located the issue, which is kind of obvious when you know it... I had an array allocated and not initially set to zero in one routine (a beginners mistake, I know), the allocation and deallocation of the arrays in the WHATEVER_* routines changed the memory state and the other routine then allocated an array in the memory where the arrays of the WHATEVER_* routines have been. By forgetting to set the newly allocated array initially to zero, it contained some values of the deallocated arrays since it apparently has been allocated into the same memory space. This forced my program to tell me that something is wrong, which did not happen when I let the arrays from the WHATEVER_* routines allocated, since then the new arrays were allocated into previously unused memory space. The values of the new array weren't zero but ridiculously small. Small enough, in fact, that my program didn't see it as 'wrong' values. 

Currently, I don't see a way that prohibits me from making the same mistake again. Shouldn't the compiler be able to tell if a value of an array has been defined before it was used? I can't think of a use-case where you would want to use the 'random' values in a newly allocated array... Or is there a way to redefine the ALLOCATE statement to allocate everything with an initial value?

Cheers

0 Kudos
Steven_L_Intel1
Employee
431 Views

Intel Inspector XE has a memory analysis feature that can detect such problems, though I can't promise it would catch yours specifically. The compiler does not do uninitialized variable checking of allocatable arrays (or of arrays at all). You can use SOURCE= on an ALLOCATE to set initial values, or if it is a derived type the type can have default values for the components.

0 Kudos
Dino_R_
Beginner
431 Views

Oh, the allocate from source is what I was looking for. I knew it existed, but I thought it would just allocate an array to be of type and shape and with the values of the array specified by 'source='. But apparently I can use it for my needs as well. Thanks

0 Kudos
Reply