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

Deallocating arrays defined from c_f_pointer

DCBoise
Novice
1,048 Views

The following code compiles using ifort, but  then fails at the deallocate statement : 

    program fort_tst
        use iso_c_binding
        INTEGER, POINTER :: a(:) 
        TYPE(C_PTR) :: ptr 
        INTEGER, POINTER :: b(:) 
ALLOCATE(a(5)) ptr = c_loc(a) CALL c_f_pointer(ptr,b,[5]) DEALLOCATE(b) end program fort_tst

The error is : 

forrtl: severe (173): A pointer passed to DEALLOCATE points to an object that cannot be deallocated
Image              PC                Routine            Line        Source             
fort_tst           000000000040C5A1  Unknown               Unknown  Unknown
fort_tst           0000000000403A17  Unknown               Unknown  Unknown
fort_tst           0000000000403812  Unknown               Unknown  Unknown
libc-2.17.so       00002AAAAB20F555  __libc_start_main     Unknown  Unknown
fort_tst           0000000000403729  Unknown               Unknown  Unknown

The pointer `b` in the code above has a proper internal array descriptor, and can be used as an alias to the array `a` in all cases, it seems, with the one exception that `b` cannot be deallocated.  

From the Intel Compiler Guide on c_f_pointer , the Intel behavior is a  design choice : 

Since the resulting data pointer fptr could point to a target that was not allocated with an ALLOCATE statement, fptr cannot be freed with a DEALLOCATE statement.

This restriction limits some really basic use cases, especially when writing wrappers for legacy Fortran code.  

Example : A Fortran subroutine S1 allocates an array. A pointer to this array is stored by C wrapper for later referencing.  A second Fortran subroutine S2 is called to de-allocate the array (passed in as C pointer stored by wrapper)  when it is no longer needed. 

A potential solution is to allocate all memory in C.  But this could require substantial code re-write, especially is a large number of arrays must be managed. 

Is there any chance that this restriction can be relaxed in future versions? 

Note:  The same code, compiled using gfortran, runs to completion.  

 

0 Kudos
11 Replies
andrew_4619
Honored Contributor II
1,036 Views

I don't quite understand your real world usage case properly to make suggestions  but I think the Intel behaviour is standard conforming.

What are you expecting, are you expecting A to be allocated  after deallocate(B)  of not? Deallocate makes the memory available for reuse but something else is using that memory that the compiler may not be able to know about at the point of deallocate. Consider the case below.  The whole point of C_LOC/c_f_pointer is communication between languages where the is no exchange of data attributes.

subroutine fort_tst()
        use iso_c_binding
        INTEGER, POINTER :: a(:) 
        !TYPE(C_PTR) :: ptr 
        INTEGER, POINTER :: b(:) 
        ALLOCATE(a(5)) 
        !ptr = c_loc(a) 
        !CALL c_f_pointer(ptr,b,[5]) 
        b => a
        DEALLOCATE(b)   ! deallocates B but not A
end subroutine fort_tst

 

DCBoise
Novice
1,027 Views

I would like to be able to allocate a pointer in subroutine A,  assign the pointer to a C pointer and store it in a C wrapper code, and once it is no longer needed, de-allocate it in subroutine B, using the stored C-pointer.    The idea is to reuse the fortran code to allocate several arrays (using the same allocate statement), and store the pointers to these arrays in the C-wrapper code.  So at any one time, the fortran code only knows about one of the arrays it has allocated.   This is a very successful approach to reuse legacy code in a minimally invasive manner. 

I realize this isn't without risk - one needs to know what they are doing.  

0 Kudos
Steve_Lionel
Honored Contributor III
1,012 Views

I think the current Intel implementation is lazy and not really meeting the letter of the standard where it refers to "the whole of an object that was created by allocation".  Intel is taking a shortcut by setting a flag in the pointer descriptor saying that deallocation is prohibited. I understand that this is attractive, but it misses valid use cases that are standard-conforming. 

I complained about this while I was still at Intel, but it's not astonishing that it was considered very low priority, since fixing it adds complication.

DCBoise
Novice
1,005 Views

It does seem that odd that `b` can be used in place of `a`  (just like in C) in all places, except for deallocation. 

0 Kudos
andrew_4619
Honored Contributor II
989 Views

My thinking may be wrong but IMO when you make a c_ptr using c_loc all you get is a handle to a memory address, you have no knowledge of what is stored there. When the programmer creates a fortran pointer using C_F_POINTER you define what is at the memory location. Is the compiler meant to track what other unrelated entities my use that address? Could it always do that in a sensible way anyway, I think not. 

0 Kudos
DCBoise
Novice
979 Views

That thought did occur to me - that `ptr = c_loc(a)` loses information stored in the array descriptor.   And so then `b` is not equivalent to `a`.   Without being able to read the array descriptor, though, it is hard to know.  

On  the other hand, `b` can be used in all contexts that `a` can be used in, e.g. `size`, `lbound`, `ubound` all work on `b` as expected.  Furthermore, at least in gfortran,  DEALLLOCATE knows exactly what to deallocate, even if a bogus shape argument is passed to `c_f_pointer`, e.g.  `c_f_pointer(ptr, b, [100])`.  So information about `a` is clearly being passed on to `b`.  The question is, why does Intel decide not to allow deallocation of `b`?   

0 Kudos
andrew_4619
Honored Contributor II
969 Views

You have defined b with c_F_pointer so the compiler knows about b. The C_PTR however could be passed into an external routine that the compiler cannot see or have knowledge of. How could that routine know what the C_PTR was pointing at to deallocate it, remember C_PTR deliberately has no descriptors to allow interchange with other languages.  There are some cases where the compiler could do it and some where it can't.  Your use of C_LOC it in your example is to trick the compiler. 

0 Kudos
DCBoise
Novice
919 Views

I agree - it does seem like that the c-ptr couldn't possibly have information about the original array a.    But then why does it work at all wth gfortran?   I have written wrappers for fairly  large fortran codes using this idea and it works flawlessly in gfortran.    

I posted a workaround, or solution (which may even be better than what I was trying above) on Stack Exchange : 
https://stackoverflow.com/questions/70922893/deallocating-arrays-defined-from-c-f-pointer/70965432#70965432 

0 Kudos
Steve_Lionel
Honored Contributor III
909 Views

The memory allocator knows what it allocated. One common implementation is to allocate some extra storage that ends up before the returned pointer address to keep track of this. 

DCBoise
Novice
891 Views

If I understand what you are saying, there is no fundamental reason why Intel couldn't do what Gfortran does.  Is that right?  And it must be the case the at something is stored at the address, because this C-ptr can be used to reference the array, set values, etc.  And it would only be able to do this is it knew something about the stride, etc.  

0 Kudos
Steve_Lionel
Honored Contributor III
885 Views

Correct - there is no fundamental reason., but it would be a significant amount of rework for what is, truthfully, a rare edge case, and would hurt performance.

Reply