- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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,
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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().
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Wow!
Jim you are fantastic! That works!!!
I would have never thought of that.
Thanks for the workaround.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page