The XL Fortran compiler contains two libraries that are geared to various memory-allocation facilities. These libraries include:
The library of most interest to Fortran users is libhmd.a. See The libhmd.a library for additional details. If you are installing an application built with these libraries in an environment that does not have XL Fortran installed, you may need to include the library libhu.a as well. This is because some routines in libhmd.a and libhm.a are dependent on routines in libhu.a.
libhm.a provides fast replacement routines for the following libm.a procedures: malloc, calloc, realloc, free, strdup, mallopt, and mallinfo. The interfaces to these routines are exactly the same as the interfaces to the standard system routines, so a user need only link in libhm.a before the system libraries to make use of them.
In addition, the following library routines that are provided in libhm.a are available to Fortran users: _heapchk, and _heapset. These routines provide production-level services that assist in maintaining consistent and correct heap storage.
Note that you cannot use the -qextname compiler option with programs that use these facilities. In other words, since these library routines are "system-like" routines that are not Fortran-specific, we do not provide "_" versions of the routines in our library.
The following table describes the additional routines that you can use from libhm.a:
C Function prototype | Fortran usage example | Description |
---|---|---|
int _heapchk(void); |
integer(4) _heapchk, retc retc = _heapchk() | Does consistency checking for all allocated and freed objects on the
heap.
Return values:
|
int _heapset (unsigned int fill); |
integer(4) _heapset, retc integer(4) fill /1/ retc = _heapset(%val(fill)) | _heapset checks the heap for consistency (similar to
_heapchk). It then sets each byte of any non-reserved
freed storage to the value of fill. The value of fill
must be an integer in the range of 0-255.
Using _heapset can help a user locate problems where a program continues to use a freed pointer to an object. Return values:
|
Example 1: Using _heapchk to test for heap errors program tstheapchk pointer (p,pbased),(q,qbased) integer pbased,qbased integer(4) _heapchk,retcode p = malloc(%val(4)) pbased = 10 ! Decrement the pointer and store into ! memory we do not own q = p-4; qbased = 10 retcode = _heapchk() if (retcode .ne. 0) call abort() ! Expected return code is: 2. Program will be aborted. call free(%val(p)) end
Example 2: Using _heapset program tstheapset pointer (p,based) integer*1 based(1000) integer _heapset,retcode p = malloc(%val(1000)) based = 1 print *,based(450:500) call free(%val(p)) retcode = _heapset(%val(2)) print *,based(450:500) end Output: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
The facilities that are provided with libhmd.a include:
You obtain access to this functionality when you link in the libhmd.a library prior to the system libraries. References to malloc, realloc, and free can be explicit, or you can obtain heap debugging for memory allocated and deallocated via the ALLOCATE and DEALLOCATE statements. To obtain source line number information in the output that the debug library produces, you should compile with the -g compiler option.
Note that you cannot specify the -qextname compiler option with programs that use these facilities.
The following shows the external interface and description of the
procedures that are provided. Note that the external interfaces and
functionality of malloc, free, calloc,
realloc, and strdup are not shown in this table, since they
have not changed.
C Function prototype | Fortran usage example | Description |
---|---|---|
void _dump_allocated (int size); |
integer(4) :: size=4 call _dump_allocated & (%val(size)) | This routine prints information to stderr about each memory block that is
currently allocated or was allocated using the debug memory management
routines. size indicates how many bytes of each memory block
are to be printed, as follows:
|
void _dump_allocated_delta (int size); |
integer(4) :: size=4 call _dump_allocated_delta & (%val(size)) | This routine prints information to stderr about each memory block that is
currently allocated or was allocated using the debug memory management
routines, since the last call to _dump_allocated or
_dump_allocated_delta. size indicates how many bytes
of each memory block are to be printed, as follows:
|
void heap_check(void); |
call heap_check() | This routine does consistency checking for memory blocks that have been
allocated using the debug memory-management routines. It checks that
your program has not overwritten freed storage, or memory outside the bounds
of allocated blocks.
All of the debug memory-allocation routines (debug version of malloc, and so on) invoke heap_check automatically. It may also be invoked explicitly in areas of code where a user believes there may be memory problems. Calling heap_check frequently can increase the memory requirements and affect the performance of a program. The HD_SKIP environment variable may be used to control how often the debug memory procedures check the heap. Note that the errors are detected when the heap_check routine is invoked, not at the point of error in the program. |
The debug libraries support the following environment variables:
For example:
export HD_SKIP=10 ! Every 10th debug memory function calls heap_check export HD_SKIP=100,10 ! After 100 calls to debug memory functions, every 10th call ! will result in a call to heap_check
Example 1: Memory leak detection pointer (p,a),(p2,b),(p3,c) ! 1 character a(4) ! 2 integer b,c ! 3 ! 4 p = malloc(%val(4)) ! 5 a(1) = 'a' ! 6 a(2) = 'b' ! 7 a(3) = 'c' ! 8 a(4) = 'd' ! 9 ! 10 p2 = malloc(%val(4)) ! 11 b = 1 ! 12 ! 13 call _dump_allocated(%val(4)) ! 14 ! 15 p3 = malloc(%val(4)) ! 16 c = 2 ! 17 ! 18 call _dump_allocated_delta(%val(4)) ! 19 end ! 20
Output: 1546-515 ----------------------------------------------------------------- 1546-516 START OF DUMP OF ALLOCATED MEMORY BLOCKS 1546-515 ----------------------------------------------------------------- 1546-518 Address: 0x20000DE0 Size: 0x00000004 (4) _int_debug_umalloc + 32C _debug_umalloc + 44 _dbg_umalloc + 18 _umalloc_init + 30 malloc + 24 _main + 24 [x.f:5] 1000022C 1546-520 Memory contents: 61626364 [abcd 1546-515 ----------------------------------------------------------------- 1546-518 Address: 0x2000DE10 Size: 0x00000004 (4) _int_debug_umalloc + 32C _debug_umalloc + 44 _dbg_umalloc + 18 malloc + 24 _main + 64 [x.f:11] 1000022C 1546-520 Memory contents: 00000001 [.... 1546-515 ----------------------------------------------------------------- 1546-517 END OF DUMP OF ALLOCATED MEMORY BLOCKS 1546-515 ----------------------------------------------------------------- 1546-515 ----------------------------------------------------------------- 1546-516 START OF DELTA DUMP OF ALLOCATED MEMORY BLOCKS 1546-515 ----------------------------------------------------------------- 1546-518 Address: 0x2000DE30 Size: 0x00000004 (4) _int_debug_umalloc + 32C _debug_umalloc + 44 _dbg_umalloc + 18 malloc + 24 _main + 8C [x.f:16] 1000022C 1546-520 Memory contents: 00000002 [.... 1546-515 ----------------------------------------------------------------- 1546-517 END OF DELTA DUMP OF ALLOCATED MEMORY BLOCKS 1546-515 -----------------------------------------------------------------
Example 2: Invalid write pointer (p,a) ! 1 integer a ! 2 ! 3 p = malloc(%val(4)) ! 4 a = 1 ! 5 p = p + 4 ! 6 a = 2 ! 7 ! 8 call heap_check() ! 9 ! 10 end ! 11 Output: 1546-503 End of allocated object 0x20000BD0 was overwritten at 0x20000BD4. 1546-514 The first eight bytes of the object (in hex) are: 0000000100000002. _int_debug_umalloc + 32C _debug_umalloc + 44 _dbg_umalloc + 18 _umalloc_init + 30 malloc + 24 _main + 24 [x.f:4] 1000022C 1546-522 Traceback: 0xD09D1C94 = _uheap_check_init + 0x24 0xD09D18C0 = heap_check + 0x28 0x100002C8 = _main + 0x5C IOT/Abort trap(coredump)