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

How Fortran free the memory allocated by C function

Jing_Q_
Beginner
2,153 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,153 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,153 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,153 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,153 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,153 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,153 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,153 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,153 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,153 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