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

deallocate returns status 173 (again)

William_Jones
New Contributor I
949 Views

I am trying to deallocate a pointer which was previously allocated but has been exchanged via a c_ptr type.  The process is captured by the following mini app:

program sample
  use, intrinsic ::  iso_c_binding, only : c_ptr, c_loc, c_f_pointer

  integer                        :: cnt=100
  integer, dimension(:), pointer :: array
  type(c_ptr)                    :: ptr
  integer, dimension(:), pointer :: temp
  integer                        :: stat
continue
  allocate(array(cnt))
  ptr = c_loc(array)
  call c_f_pointer(ptr,temp,[cnt])
  deallocate(temp, stat=stat)
  write(*,*) "Status:",stat
end program sample

While this works in Intel 17.0.2, it generates a Status = 173 for Intel Fortran 18.0.0 and 19.0.1.144.

Any help or suggestions appreciated,

0 Kudos
1 Solution
William_Jones
New Contributor I
949 Views

Thanks for the reply.  It is appreciated.  However, this is but a sample of what I'm trying to do.  The c_ptr is passed around as part of an interoperable type (and between languages).  Therefore, it is not as simple as just deallocating the original array pointer.  I no longer have it.

I have, however, come up with a workaround which is attached.  This is somewhat convoluted, but it does what I need.

I think it a serious design flaw that the "standard" allows one to get the address of a Fortran pointer with c_loc() and then convert that address back to a Fortran pointer of the same kind, rank, etc., but does not allow you to deallocate it.  While I appreciate the feedback, I'm not interested the debate.

View solution in original post

0 Kudos
16 Replies
Steve_Lionel
Honored Contributor III
949 Views

Intel Fortran keeps a flag in array pointers that says whether the pointer is allowed to be deallocated. This flag is cleared if you do pointer assignment to a part of an allocated thing, but the compiler sometimes doesn't recognize when the assignment is the whole thing. Your use of c_loc and c_f_pointer further hides from the compiler what is happening. I'm a bit astonished that this ever worked.

The standard says "If a pointer appears in a DEALLOCATE statement, it shall be associated with the whole of an object that was created by allocation." Unfortunately, ifort takes a shortcut in its test for this.

In order for this to work, the run-time would need to compare address and length for the allocation. Clearly this is feasible, as most memory managers need to do this anyway. I remember having many discussions with the development team about the holes in the current strategy, but don't know the current state of things.

I'd recommend filing a support request at the Online Service Center about this.

0 Kudos
William_Jones
New Contributor I
949 Views

Thanks.  I'll try to get this looked at through the Online Service Center.

I will say that this seems to work as expected in: gfortran 4.8.5, 6.4.0, 8.1.1; PGI 18.7; and XLF 16.1.1.  I also successfully verified that it worked with Intel Fortran 15.0.3 as well.  I do wish Intel exercised a more extensive regression test suite on the Fortran compiler.

0 Kudos
jimdempseyatthecove
Honored Contributor III
949 Views

William, CAUTION

"seems to work as expected", IOW no status error, is no indication that it is actually working. For example, do you note the glaring error in your code in #1?

The error (in a sense) is array pointer is still associated the former block of allocated memory.

FWIW, maybe Steve can recollect things

ptr => array
and
call c_f_pointer(ptr,tmp,[cnt])

should be creating array descriptors that indicate deletion forbidden. Pointer to a scalar would be harder to maintain.
The array descriptor for the original allocation should contain a reference counter as well, but I am fairly certain that it doesn't for performance reasons (IOW it befalls upon the programmers not to shoot themselves in their feet).

Jim Dempsey

0 Kudos
William_Jones
New Contributor I
949 Views

Jim,

Thanks for the reply.  Actually, I do not see the glaring error nor do I understand what I think is your description of it.

However, I do think the code is working "as expected" not simply because of the status error, but because when I execute it through `valgrind` it indicates that the memory is indeed deallocated.  This actually is the case for Intel Fortran 18.0.3 and 19.0.1.144 as well if I retrieve, but ignore the status code.

The status code returned by Intel Fortran 18.0.3 and 19.0.1.144 is 173 and, from the Intel documentation, a non-zero status indicates an error: "If the deallocation is successful, the variable is set to zero. If the deallocation is not successful, an error condition occurs, and the variable is set to a positive integer value (representing the run-time error)".

I have also now added Intel Fortran 14.0.3 and 16.0.3 to the mix.  They too return a status of zero from deallocate().

0 Kudos
jimdempseyatthecove
Honored Contributor III
949 Views

Some of the prior versions of Fortran had an error (oversight, bug, ...) that would set an error code into the STAT= variable the on error...
... but leave the prior contents of the as-was on success (as opposed to zeroing it). Try setting your STAT= variable to 0 prior to the deallocate. If this eliminates the error status, then this bug has resurfaced.

Jim Dempsey

0 Kudos
William_Jones
New Contributor I
949 Views

Wow!

Jim you are fantastic!  That works!!!

I would have never thought of that.

Thanks for the workaround.

0 Kudos
jimdempseyatthecove
Honored Contributor III
949 Views

I might venture to guess that when deallocating multiple entities that the STAT= error variable is to receive the inclusive OR of the error code(s)... but that the initial value was not zeroed. Interestingly, this would also provide for multiple DEALLOCATES to accumulate error, but the statement is not documented this way.

Jim Dempsey

0 Kudos
William_Jones
New Contributor I
949 Views

Oops.  Not so fast.  I had modified my test code trying to debug.  I added the following line just before the deallocate statement:

temp => array

Removing that line obviously is the reason that it worked.

Sorry for the false jubilation.

0 Kudos
William_Jones
New Contributor I
949 Views

Additionally, #5 above is incorrect.  When the status is returned as 173 (Intel Fortran 18.0.3 and 19.0.1.144) the memory is not deallocated.

0 Kudos
FortranFan
Honored Contributor II
949 Views

William Jones wrote:

.. Any help or suggestions appreciated,

@William Jones,

You write in your original post, "Any help or suggestions appreciated,"

Look in the Fortran standard e.g., section 6.7.3.3 Deallocation of pointer targets in document 10-007r1 toward Fortran 2008 to find, "Deallocating a pointer ..  whose target was not created by an ALLOCATE statement causes an error condition in the DEALLOCATE statement."

So suggestion #1: do not use DEALLOCATE statement with a pointer whose target was not created by an ALLOCATE statement!

Fortran standard and Intel Fortran compiler are increasingly getting better and better, rely on them!

Consider the following slight modification to your code to extract the error message with the intrinsic functions:

program sample
   use, intrinsic ::  iso_c_binding, only : c_ptr, c_loc, c_f_pointer

   integer                        :: cnt=100
   integer, dimension(:), pointer :: array
   type(c_ptr)                    :: ptr
   integer, dimension(:), pointer :: temp
   integer                        :: stat
   character(len=2048)            :: msg
continue
   allocate(array(cnt))
   ptr = c_loc(array)
   call c_f_pointer(ptr,temp,[cnt])
   deallocate(temp, stat=stat, errmsg=msg)
   if ( stat /= 0 ) then
      print *, "Deallocation of temp failed: stat = ", stat
      print *, trim(msg)
   else
      print *, "Deallocation of temp is successful."
   end if
   deallocate(array, stat=stat, errmsg=msg)
   if ( stat /= 0 ) then
      print *, "Deallocation of array failed: stat = ", stat
      print *, trim(msg)
   else
      print *, "Deallocation of array is successful."
   end if
end program sample

Upon execution with Intel Fortran 19.0 Update 1, the output is:

 Deallocation of temp failed: stat =  173
 A pointer passed to DEALLOCATE points to an object that cannot be deallocated
 Deallocation of array is successful.

 

0 Kudos
William_Jones
New Contributor I
950 Views

Thanks for the reply.  It is appreciated.  However, this is but a sample of what I'm trying to do.  The c_ptr is passed around as part of an interoperable type (and between languages).  Therefore, it is not as simple as just deallocating the original array pointer.  I no longer have it.

I have, however, come up with a workaround which is attached.  This is somewhat convoluted, but it does what I need.

I think it a serious design flaw that the "standard" allows one to get the address of a Fortran pointer with c_loc() and then convert that address back to a Fortran pointer of the same kind, rank, etc., but does not allow you to deallocate it.  While I appreciate the feedback, I'm not interested the debate.

0 Kudos
FortranFan
Honored Contributor II
949 Views

William Jones wrote:

.. this is but a sample of what I'm trying to do.  The c_ptr is passed around as part of an interoperable type (and between languages). ..  I no longer have it.

.. I'm not interested the debate.

@William Jones.

Most readers, especially I, are not interested in a debate; you were looking for suggestions and you got some.

And another suggestion is if you can consider using objects with ALLOCATABLE attribute, since the introduction of enhancements with it in Fortran 2003, it appears rather preferrable to those with the POINTER attribute:  In this case, you do not need to worry about deallocating anything.

program sample
  use, intrinsic ::  iso_c_binding, only : c_ptr, c_loc, c_f_pointer

  integer                        :: cnt=100
  integer, dimension(:), allocatable, target :: array
  type(c_ptr)                    :: ptr
  integer, dimension(:), pointer :: temp
  integer                        :: stat
continue
  allocate(array(cnt))
  ptr = c_loc(array)
  call c_f_pointer(ptr,temp,[cnt])
  ! And when done
  temp => null()
  stop "SUCCESS!"
end program sample

Upon execution,

SUCCESS!

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
949 Views

It appears that you want the functionality of C pointers in Fortran. Therefore, an alternative that you may find useful, is to perform all your allocations and deallocations with C functions.

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor II
949 Views

To add to Quote #13: if you have to employ objects with POINTER attribute in Fortran, then you can consider a data management module and handle the "creation" and "deletion" of pointers in there, as shown below.  And you can make use of this in your mixed language code, assuming a companion C processor is involved.

module DataMgr
   use, intrinsic ::  iso_c_binding, only : c_int, c_ptr, c_loc, c_f_pointer
   implicit none
   integer, dimension(:), pointer, save :: array => null()
contains
   function NewArray( cnt ) result( pArr )
      integer(c_int), intent(in), value :: cnt
      type(c_ptr) :: pArr
      ! Elided is handling of existing 'array' object
      allocate( array(cnt) )
      pArr = c_loc( array )
      return
   end function
   subroutine DeleteArray( pArr, cnt, stat, msg )
      ! Argument list
      type(c_ptr), intent(in), value    :: pArr
      integer(c_int), intent(in), value :: cnt
      integer(c_int), intent(inout)     :: stat
      character(len=*), intent(inout)   :: msg
      ! Local variables
      integer, dimension(:), pointer :: temp
      call c_f_pointer( pArr, temp, [ cnt ] )
      if ( associated(temp, array) ) then
         deallocate(array, stat=stat, errmsg=msg )
         array => null()
      end if
      return
   end subroutine DeleteArray
end module DataMgr
program sample
   use, intrinsic ::  iso_c_binding, only : c_ptr
   use DataMgr, only : NewArray, DeleteArray
   implicit none
   integer             :: cnt=100
   type(c_ptr)         :: ptr
   integer             :: stat
   character(len=2048) :: msg
   continue
   ptr = NewArray( cnt )
   call DeleteArray( ptr, cnt, stat, msg )
   if ( stat /= 0 ) then
      print *, "Delete Array failed: stat = ", stat
      print *, trim(msg)
      stop "FAILURE :-("
   end if
   stop "Delete successful!"
end program sample

Upon execution.

Delete successful!

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
949 Views

FF,

This requires that the original allocated array pointer persist through use of the returned c_ptr.

In the OP's scheme, the array of pointers "array" would have to maintain the Fortran allocated pointer, then the DeleteArray subroutine would have to search the pointer array for a match (or lack thereof). The OP did not want to do this.

The OP wants C-like behavior. Fortran is not designed this way. As I see it, the two options are: stick with Fortran design rules or perform the allocations and deallocations in C.

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor II
949 Views

jimdempseyatthecove wrote:

.. This requires that the original allocated array pointer persist through use of the returned c_ptr. ..

See Quote #15 and the suggestion using a data management module code.

I'm not sure what OP wants - the indication per  Quote #12 is " c_ptr is passed around as part of an interoperable type (and between languages)".  Now if a scheme as shown in Quote #15 with the DataMgr module is followed, then the match you are talking about can be managed by that module - see an example with the check ASSOCIATED( temp, array ) .

Now if OP"s actual need is for the Fortran side of things to do all the heavy lifting in terms of computations only and Fortran code is really library code called by other libraries (or executable) in another language, and it doesn't matter in that scheme who is doing the allocations and deallocations, then as you indicate, it may be simpler for OP to manage the data including their freeing on the caller side.

0 Kudos
Reply