  J      CMEM - A Tool for Debugging 'C' Memory Allocation Routines on OpenVMS   						V1.0 - May 1995  						OpenVMS VAX/Alpha V6.1    8 Copyright  1995 Humbug Solutions.  All rights reserved.  M No waranties, guarentees or cookies, expressed, implied or baked are provided 8 with this software.  Nobody is responsible for anything.  C You may freely use and redistribute this software, just include the H legal mumble-jumble.  Also, let's not have a bunch of disparate versionsI of this thing floating around.  If you have some changes, send them to me ; and I'll incorporate them into the "official" distribution.      INTRODUCTION  I This package provides updated versions of the C run-time library routines I 'malloc', 'calloc', 'realloc', and 'free'.  The new versions provide many K features to insure the integrity of the C dynamic memory pool.  Programmers G can use this information to track down routines which improperly access  dynamic memory.   K It has been tested on OpenVMS VAX with the VAX C compiler and OpenVMS Alpha  using DEC C.  " What does this package do for you?  E    o	No changes are required to your source code.  You do not need to @ 	re-compile, but CMEM is able to display more detailed tracebackC 	information if each module is compiled using the /DEBUG qualifier. : 	You do need to re-link the image to access CMEM routines.  4    o	The routines work on both VAX and Alpha CPUs.    M    o    CMEM can be configured to allocate memory so that it ends with a page A 	of protected memory.  This will cause an access violation if any B 	instruction attempts to read or write beyond the allocated space.  H    o    The page before allocated space can be protected, but there will@ 	likely be some space between the allocated memory start and the> 	previous (protected) page.  This will be filled with the 0xAA@ 	bit pattern.  If memory is ever released (via 'free') with that, 	pattern changed, an error will be signaled.  F    o    You can request that the call stack be recorded when memory isB 	allocated.  This provides a mechanism for determing who allocatedB 	memory that was never released.  A CMEM subroutine is provided toD 	display the call stack.  Another routine allows the user to tag all@ 	current entries to not be displayed (i.e. the entries represent 	permanently allocated memory).   A    o	An error is reported if an attempt is made to release memory < 	that has not been allocated (or has already been released).  H    o    Memory allocated via 'malloc' will have each byte set to 0xAA so@ 	that use of uninitialized memory can be detected.  0xAA has theA 	sign bit set which should (hopefully) cause access violations if C 	used as an pointer.  Also, the alternating 10101010 pattern should ( 	be easily detected within the debugger.  B    o    A user can request that released memory will just have the@ 	page protection changed rather than returning it to pool.  This> 	will allow the user to detect use of heap that was previously
 	released.  $ And just what can't this package do:  F    o	Shareable image files have already resolved the external linkages? 	to the C run-time library.  We won't be able to monitor memory F 	allocation requests from within the shareable image.  However, if youC 	are building your own shareable image, you should still be able to $ 	test your code with these routines.  F    o	I didn't bother to try and protect myself against all the variousB 	qualifiers which can be used with DEC C.  Specifically, don't try= 	to get too fancy with the /PREFIX_LIBRARY_ENTRIES qualifier.      HOW TO USE THESE ROUTINES   4 Begin by compiling the three modules as shown below:   	$ CC/DEBUG/NOOPTIMIZE CMEM.C ' 	$ CC/DEBUG/NOOPTIMIZE CMEM_TRACEBACK.C  	$ MESSAGE CMEM_MESSAGE.MSG   K I don't bother optimizing the routines as they are intended to be used when  debugging your programs.  H Next, link the resulting object files (CMEM.OBJ, CMEM_TRACEBACK.OBJ, andK CMEM_MESSAGE.OBJ) into your image.  (There is a linker option file provided N which lists these three object files).  They should be listed before your linkK command line accesses the C run-time library (or IMAGELIB.OLB).  Be sure to I link using the /TRACEBACK qualifier so that we can translate addresses to L source code line numbers.  Also, to control CMEM and display the statistics,O you will want to link with the debugger (/DEBUG qualifier on the LINK command).   ? On an Alpha, you will get the following messages when you link:   2 	%LINK-W-MULDEF, symbol DECC$FREE multiply definedA 	        in module DECC$SHR file SYS$COMMON:[SYSLIB]DECC$SHR.EXE; 5 	%LINK-W-MULDEF, symbol DECC$REALLOC multiply defined A 	        in module DECC$SHR file SYS$COMMON:[SYSLIB]DECC$SHR.EXE; 4 	%LINK-W-MULDEF, symbol DECC$MALLOC multiply definedA 	        in module DECC$SHR file SYS$COMMON:[SYSLIB]DECC$SHR.EXE; 4 	%LINK-W-MULDEF, symbol DECC$CALLOC multiply definedA 	        in module DECC$SHR file SYS$COMMON:[SYSLIB]DECC$SHR.EXE;   I These messages are OK and tell you that we have replaced the standard DEC  supplied routines.  G On the VAX, you will want to link with the VAXCRTL object library.  You B can't link with the shareable image as the linker will resolve theJ globals from VAXCRTL.EXE rather than from our object modules.  Yep, that's  just how things work on the VAX.  I Next, run the image and type GO at the debugger prompt to get to the main J routine (if you aren't already there).  Then issue the command 'SET MODULEJ CMEM'.  This provides access to the user interface routines.  You then useL the debugger CALL command to control CMEM.  The routines you can invoke are:   cmem_collect_stack( state )   
    parameter:   7 	state:		0 - disable recording call stack at allocation 0 			1 - enable recording call stack at allocation  M    When a block of memory is allocated, we record the call stack.  To improve M    performance, you can disable collection of this information.  As a result, C    when you request information about the allocated memory (via the G    'cmem_show_blocks' routine), we will not be able to display the call 	    stack.   6    The default setting is to collect this information.     cmem_collect_time( state )  
    parameter:   * 	state:		0 - disable time stamp collection# 			1 - enable time stamp collection   J    When a block of memory is allocated, we record the current system time.K    To improve performance, you can disable collection of this information.  L    As a result, when you request information about the allocated memory (viaN    the 'cmem_show_blocks' routine), we will not be able to show the allocation    time.  6    The default setting is to collect this information.     cmem_boundary_check( state )  
    parameter:   3 	state:		0 - densely pack allocated memory segments 5 			1 - place protected memory around allocated blocks   N    Sometimes code will write beyond the end of an allocated segment of memory.K    By enabling boundary check, the attempted write will cause the offending K    instruction to get an access violation (rather than modifying some other     piece of data).  K    The unfortunate side effect is that we will devour the available virtual G    address space very quickly.  For example, if you request 10 bytes of L    information on an Alpha with an 8 KByte page size, we will need 24 KBytesF    of virtual address space (1 page to hold the allocated memory and 2-    for the protected pages before and after).   5    The default setting is to NOT use protected pages.      cmem_protect_freed( state )   
    parameter:   ' 	state:		0 - release page table entries 0 			1 - protect released memory againt all access  K    Poorly designed code may attempt to use memory that has been released by I    calling the 'C' run-time routine 'free'.  To detect this, the released O    memory can be protected such that any access will cause an access violation.   L    Note that this feature is only available blocks of memory allocated while=    boundary checking was enabled (see 'cmem_boundary_check').   H    The consequence of not releasing memory is that virtual address spaceH    utilization will constantly increase.  Eventually you will abort with    a VASFULL error.   7    The default setting is to allow memory to be reused.      cmem_reset_display_flags( )       no parameters  K    When an application starts up, it normally allocates some memory for the J    life of the image.  You may not wish to have such memory displayed whenK    listing blocks of memory which are in use.  This routine will set a flag I    indicating that the associated information is not to be displayed when      'cmem_show_blocks' is called.     cmem_check_address( address )   
    parameter:   A 	address:	Memory address to check to see if it is associated with ! 			a allocated segment of memory.   M    When boundary checking is enabled, you will get an access violation should J    someone access memory outside what was allocated.  In that case, it mayJ    be desirable to display information about any memory segment associated4    with the virtual address of the access violation.  G    This routine takes an address and will display information about any F    block (allocated with boundary check enabled) which has the address     within a boundary check page.     cmem_show_blocks( )       no parameters  L    Displays the current list of allocated blocks of memory.  It displays theK    address returned by 'malloc', 'calloc', or 'realloc' and the size of the L    block.  If statistic collection was enabled when the block was allocated,9    the allocation time and call stack are also displayed.   =    Some allocated blocks will not be displayed if the routine @    'cmem_reset_display_flags' was called after it was allocated.     DEBUGGING TECHNIQUES  9 Here are some examples of how this package might be used.   
 Example 1:  L When running, your image keeps using more and more virtual address space andL it eventually aborts with insufficient virtual memory.  You can't figure outJ which routine is allocating memory and failing to return it to the dynamic memory pool.  <    1)	Link the image with CMEM and use the /DEBUG qualifier.  5 	$ LINK/DEBUG mycode,CMEM,CMEM_TRACEBACK,CMEM_MESSAGE   K    2)	Start the image and enable statistic collection (which is actually on + 	by default -- but hey, this is an example:   
 	$ RUN mycode   * 		OpenVMS Alpha AXP DEBUG Version V6.1-00R  8 	%DEBUG-I-INITIAL, language is C, module set to <mycode>< 	%DEBUG-I-NOTATMAIN, type GO to get to start of main program   	DBG> GO 	break at routine <mycode>\main  	DBG> SET MODULE CMEM " 	DBG> CALL cmem_collect_stack( 1 )/ 	%CMEM-I-INIT, malloc/free monitoring has begun G 	%CMEM-I-BNDRYPRTENA, boundary check for newly allocated memory enabled  	value returned is 144801827 	DBG> GO  I    3)	Let your code run until it has allocated all dynamic memory that it ? 	will need.  Stop the run with 'CTRL/Y' and type 'DEBUG' if the B 	DCL prompt appears.  Next, mark all allocated blocks so that they 	won't be displayed later.   	*INTERRUPT* 	$ DEBUG# 	DBG> CALL cmem_reset_display_flags 6 	nnn blocks currently in use and will not be displayed 	value returned is 1 	DBG> GO  K    4)	Let your code continue on.  Stop it and check for any newly allocated % 	blocks which have not been released:    	*INTERRUPT* 	$ DEBUG 	DBG> CALL cmem_show_blocks    	Allocated blocks of memory:  E 	001DB800: 12 bytes allocated at  3-MAY-1995 19:15:07.69; call stack: 1 	  1: PC = 00030170    <mycode>\main\%LINE 704+20 * 	  2: PC = 00030080    <mycode>\__main+128' 	  3: PC = 88E07AD8    no symbolization ' 	  4: PC = 7FA202E0    no symbolization    	value returned is 1  G    5)	Determining why the block has not yet been released is up to you. A 	You know who requested the allocation.  Now, who was supposed to  	release it?    
 Example 2:  F You want to check and see if you're writing or reading past the end of an allocated memory segment.  <    1)	Link the image with CMEM and use the /DEBUG qualifier.  ! 	$ LINK/DEBUG mycode,CMEM.OPT/OPT   1    2)	Start the image and enable boundary checks.   
 	$ RUN mycode   * 		OpenVMS Alpha AXP DEBUG Version V6.1-00R  8 	%DEBUG-I-INITIAL, language is C, module set to <mycode>< 	%DEBUG-I-NOTATMAIN, type GO to get to start of main program   	DBG> GO 	break at routine <mycode>\main  	DBG> SET MODULE CMEM # 	DBG> CALL cmem_boundary_check( 1 ) / 	%CMEM-I-INIT, malloc/free monitoring has begun . 	%CMEM-I-STATENA, statistic collection enabled 	value returned is 144801827 	DBG> GO  J    3)	Let your code run.  You will get an access violation if you have any
 	problems.    $ RUNNING OUT OF VIRTUAL ADDRESS SPACE  L Okay, so you run out of virtual address space.  What's a person to do?  MostJ likely this occurs because you have enabled boundary checks which requires# lots of memory.  Try the following:   E    1)	You most likely have hit your process page file quota.  You can B 	confirm this by comparing the value of "Peak virtual size" from aD 	SHOW PROCESS/ACCOUNTING command to the value of "Paging file quota"A 	from a SHOW PROCESS/QUOTA command.  If the virtual size is close @ 	to or greater than the page file quota, have the system manager+ 	go into authorize and increase your quota.   B 	The system manager should make sure that there is sufficient pageC 	file space available to support the new quota.  You will also need 7 	to log out and back in again to pick up the new quota.   J    2)	Make sure that the VIRTUALPAGECNT SYSGEN parameter allows the numberF 	of pages you think you will need.  As changing this requires a systemC 	reboot, I would tend to increase it in large chunks.  The negative C 	side of increasing this value is that it adds to the size of every  	process header.  J    3)	When boundary checks are enabled, allocating a huge chunk of dynamicE 	memory and then grabbing a piece for static data will eat up virtual C 	address space.  (This is because we use $EXPREG and $DELTVA system E 	services).  Try to allocate "static" type data early in the code and D 	then the dynamic data can come and go without permanently eating up 	the address space.       FILES WHICH MAKE UP THIS PACKAGE  1 The following files are included in this package:   F    AAAREADME.TXT	Just a quick summary of what this package does.  More 			details in CMEM.TXT.   @    CMEM.C		Replacements for C 'malloc', 'calloc', 'realloc', and8 			'free' along with user routines to manipulate several 			features of the package.   @    CMEM.OPT		A linker option file appropriate for user programs.      CMEM.TXT		This file.   H    CMEM_MESSAGE.MSG	VMS messages which we use to display stuff (that's a! 			technical term) to SYS$OUTPUT.   >    CMEM_TEST.C		A simple test program to check out the various4 			capabilities of this package.  THIS SHOULD NOT BE 			LINKED WITH YOUR CODE.   B    CMEM_TEST.COM	A DCL command procedure to build and run the test 			program.   A    CMEM_TRACEBACK.C	Provides support for translating addresses to 4 			source line numbers.  No, this doesn't manipulate5 			the undocumented debug symbol table -- it uses the   			VMS debugger in a subprocess.     WHAT DOES THE FUTURE HOLD?  J There never is enough time to do everything.  I probably won't do any moreI on this package unless people are actually finding it useful.  Should you 5 have any comments or suggestions, please send them to  "hunsaker@eisner.decus.org".  M It would be really handy if we could intercept the C RTL calls from pre-built M shareable images (especially for something like DECwindows).  It shouldn't be J too hard to build a shareable image that would pass on most calls and justH divert the dynamic memory management routines.  Hmm, let's see just what) we can do to trick the image activator...   H When enabling boundary checks, you should be able to specify whether theL allocated segment is positioned such that the protected space is immediately before or after the segment.  I When allocating without boundary checks enabled, the code should put some J extra space around the segment and fill it with the 0xAA pattern.  If thatK pattern has been changed when freeing the block, we should signal an error. 