XL Fortran for AIX 8.1

User's Guide


Using Debug Memory Routines for XL Fortran

The XL Fortran compiler contains two libraries that are geared to various memory-allocation facilities. These libraries include:

libhmd.a
A library that provides debug versions of memory-management routines.

libhm.a
A non-debug library that provides replacement routines for malloc, free, and so on. These routines are faster than the usual AIX versions. In addition, this library contains a few new library routines to provide additional facilities for memory management and production-level heap error checking.

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.

The libhm.a library

libhm.a provides fast replacement routines for the following libc.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:

0
The heap is consistent.

1
Reserved.

2
Heap errors have occurred.
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:

0
The heap is consistent.

1
Reserved.

2
Heap errors have occurred.

Examples:

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
Example 3:  Using _heapchk to test for heap errors with ALLOCATE and DEALLOCATE
 
	     program tstheapchk
	       integer, allocatable :: a(:)
	       integer(4) :: retcode
	       integer(4), external :: _heapchk
 
	       allocate(a(1:5))
 
       ! Store outside the bounds of allocated memory.
	       a(-5:10) = 17
 
	       retcode = _heapchk()
	       if (retcode /= 0) call abort()
	       print *, retcode
 
	       deallocate(a)
     end program tstheapchk
Example 4:  Using _heapset with memory managed with ALLOCATE and DEALLOCATE
 
     program tstheapset
	       integer(1), pointer :: p1(:), p2(:)
	       integer(4) :: retcode
	       integer(4), external :: _heapset
 
	       allocate(p1(1:10))
	       p2 => p1(6:10)
	       p1 = 1
	       print *, p2
 
	       deallocate(p1)
 
	       retcode = _heapset(%val(2))
	       print *, p2
     end program tstheapset
 
Output:
 1 1 1 1 1
 2 2 2 2 2

The libhmd.a library

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:

Negative size
All bytes are displayed.

0 size
No bytes are displayed.

Positive size
Specified number of bytes are displayed.
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:

Negative size
All bytes are displayed.

0 size
No bytes are displayed.

Positive size
Specified number of bytes are displayed.
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.

Environment Variables

The debug libraries support the following environment variables:

HD_SKIP=increment [,start]
Control how often heap_check is invoked from the debug versions of the memory-management routines. increment indicates how often you want the debug functions to check the heap. start specifies that the skipping of heap checks should begin after the debug memory routines have been called a certain number of times. The default values for increment and start are 1 and 0, respectively.

HD_FILL
When this environment variable is exported, the debug versions of malloc and realloc set the memory allocated to a byte pattern of 0xAA.

HD_STACK=n
n specifies how many procedures should appear in the call chain that the debug memory routines produce. The default is 10, or it is the number of routines in the call chain, if fewer than 10.

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.

Examples:

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)
 


[ Top of Page | Previous Page | Next Page | Table of Contents | Index ]