Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs have moved to the Altera Community. Existing Intel Community members can sign in with their current credentials.

How Fortran free the memory allocated by C function

Jing_Q_
Beginner
2,494 Views

I have Fortran main program to call C function that retrun a dynamic array. In the C function, it uses malloc() to allocate the array. How Fortran can free the allocated array by C?

Thanks a lot!

Here is my Fortran program example:

Program main
    USE ISO_C_BINDING
    IMPLICIT NONE

    !  INTERFACE block must set up the interface between C and Fortran.
    INTERFACE
    SUBROUTINE c_sub(dim, W_ptr) BIND (C,NAME='c_sub')
    USE ISO_C_BINDING
    INTEGER (c_int) ::dim   
    type(c_ptr)     :: W_ptr
    !DEC$ ATTRIBUTES REFERENCE :: W_ptr ! necessary for the interface
    END SUBROUTINE ExecuteMOR
    END INTERFACE

    ! local variable
    INTEGER :: dim, i
    REAL*8, allocatable,DIMENSION(:) :: W
    REAL*8, DIMENSION(:), pointer    :: W_fptr     
    type (c_ptr) :: W_ptr   

    call c_sub(dim, W_ptr)

    ! convert c pointer to fortran pointer
    CALL C_F_POINTER(W_ptr, W_fptr, dim)

    ! allocate W as new size
    allocate(W(dim))
    do i = 1, dim
       W(i) = W_fptr(i)
    end do

    ...
    deallocate(W)
    how to free memory W_ptr???
    END program main

   The C function is like that:
    void c_sub(int *dim, double **W_ptr)
    {
        *dim = 5;
        *W      = (double *)malloc((*dim)*sizeof(double));
    }

0 Kudos
9 Replies
Jing_Q_
Beginner
2,494 Views

I tried to pass W_ptr to another c function and free it. But it doesn't work.

0 Kudos
JVanB
Valued Contributor II
2,494 Views

You don't need the !DEC$ ATTRIBUTES REFERENCE in the interface body for c_sub. Reference is already the default for subroutines with the BIND attribute. To override the default you could give W_ptr the VALUE attribute, but you don't want to do that because you want to return a result through this dummy argument.

Passing W_ptr to another C function to free it should work if you get the level of indirection right as you did with your interface for c_sub. If you can't get it to work show the c function, the Fortran interface body, and the Fortran invocation.

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,494 Views

When you END the PROGRAM the Process terminates. Terminating the process returns the C heap regardless of any dangling allocations.

I suggest you consider adding a "c_sub_free" funciton to deallocate the C allocated memory when it is no longer needed. Note, at some point in the future you might want to use C++ with new/delete and non-default dtor.

Jim Dempsey

0 Kudos
Jing_Q_
Beginner
2,494 Views

Hi, Jim:

I followed your suggestion and created another C function to free memory. But it did not work. The program report accessing error during the free() in C function. Can you give me some suggestion? Here is fortran code

Program main
    USE iso_c_binding
    IMPLICIT NONE

    !  INTERFACE block must set up the interface between C and Fortran.
    INTERFACE
    SUBROUTINE c_sub(dim, W_ptr) BIND (C,NAME='c_sub')
    USE ISO_C_BINDING
    INTEGER (c_int) ::dim   
    type(c_ptr)     :: W_ptr
    END SUBROUTINE c_sub

    SUBROUTINE c_subfree(dim, W_ptr) BIND (C,NAME='c_subfree')
    USE ISO_C_BINDING
    INTEGER (c_int) ::dim   
    type(c_ptr)     :: W_ptr
    END SUBROUTINE c_subfree
   
    END INTERFACE

    ! local variable
    INTEGER :: dim, i
    REAL*8, allocatable,DIMENSION(:) :: W
    REAL*8, DIMENSION(:), pointer    :: W_fptr     
    type (c_ptr) :: W_ptr   

    call c_sub(dim, W_ptr)

    ! convert c pointer to fortran pointer
    call c_f_pointer(W_ptr,W_fptr, [dim])

    ! allocate W as new size
    allocate(W(dim))
    do i = 1, dim
       W(i) = W_fptr(i)
    end do

    deallocate(W)
    call c_subfree(dim,W_ptr)
    
END program main

C code is:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
void c_sub(int *dim, double **W_ptr)
    {
        *dim = 5;
        *W_ptr = (double *)malloc((*dim)*sizeof(double));
    }

void c_subfree(int *dim, double **W_ptr)
    {
        free(*W_ptr);
    }

0 Kudos
JVanB
Valued Contributor II
2,494 Views

Well, I'm stumped. Your code looks fine to me and in fact runs to completion without error in gfortran/gcc.

0 Kudos
IanH
Honored Contributor III
2,494 Views

...and ifort (though I think the value of W_fptr is undefined, so the program is technically non-conforming)

[plain]>cl /c "2013-04-02 c.c" && ifort /check:all /warn:all /stand:f03 /standard-semantics "2013-04-02 fortran.f90" "2013-04-02 c.obj" && "2013-04-02 fortran.exe" && echo All done
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

2013-04-02 c.c
Intel(R) Visual Fortran Compiler XE for applications running on IA-32, Version 13.1.1.171 Build 20130313
Copyright (C) 1985-2013 Intel Corporation.  All rights reserved.

2013-04-02 fortran.f90(23): warning #6916: Fortran 2003 does not allow this length specification.   [8]
    REAL*8, allocatable,DIMENSION(:) :: W
---------^
2013-04-02 fortran.f90(24): warning #6916: Fortran 2003 does not allow this length specification and using it in new code is silly, get out of the habit now.   [8]
    REAL*8, DIMENSION(:), pointer    :: W_fptr
---------^
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

"-out:2013-04-02 fortran.exe"
-subsystem:console
"2013-04-02 fortran.obj"
"2013-04-02 c.obj"
All done
[/plain]

0 Kudos
Jing_Q_
Beginner
2,494 Views

I used Intel fortran composer 2013 (64bit) and MS visual studio 2010. In fact, my C code was compiled as static library and then was linked to my Fortran code. In addition, my C code also linked some dll too. But my code is very similar to the test example as I posted. During the debuging, error reports when call the free() function as:

This may be due to a corruption of the heap, which indicates a bug in test.exe or any of the DLLs it has loaded.

This may also be due to the user pressing F12 while test.exe has focus.

In output windows it says:

HEAP[test.exe]: Invalid address specified to RtlValidateHeap( 0000000002360000, 000000000E71FDD0 )
Windows has triggered a breakpoint in test.exe.

The output window may have more diagnostic information

 I am confused!! Thanks in advance for any suggestion. 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,494 Views

Use "real(8)" not "real*8" top avoid the warning.

Using VS 2010 SP1Rel, Intel C++ 2011.9.300, and IVF 2011.10.325

All combinations of MSC++/ICC/IVF/32-bit/64-bit run to completion (at least for Debug build).

Note, I had an issue where the project did not rebuild the static lib when using MS C++. Had to clean after switching C++ compilers.

Jim Dempsey

0 Kudos
Jing_Q_
Beginner
2,494 Views

I finally figured out the problem.  In my real code, the pointer created by malloc() was wrongly assigned to a pointer created by a dll. That's why I wasn't able to free it since the dll is finished. The example code, which I posted here, indeed works well.

 Thank you guys very much!!

0 Kudos
Reply