NASD Programmer's Documentation
Memory Allocation and Deallocation

NASD provides its own interfaces for memory allocation and deallocation. These should be used in preference to platform-provided interfaces (such as malloc() and free()) to provide greater portability, readability, and debugability to code. The NASD memory interface includes mechanisms for detecting and identifying core leaks as well as limited bounds-checking (fenceposting).

To use the NASD memory interface, a file must include <nasd/nasd_mem.h>. To initialize the memory module, call nasd_mem_init(). Like most module initialization functions, this requires no arguments. When the module is no longer needed, call nasd_mem_shutdown(). Note that the interface should be shut down only after freeing allocated memory.

In addition to module initialization and shutdown, the memory module provides two key entrypoints:

NASD_Malloc(pointer, size, cast)
NASD_Free(pointer, size)
These interfaces behave in the manner that experienced C programmers are likely to expect. NASD_Malloc() assigns to pointer a valid pointer to size bytes of memory, using cast as a typecast for this assignment. To release memory acquired from a call to NASD_Malloc(), one calls NASD_Free() with the first argument being pointer as returned by NASD_Malloc(), and the second argument being the number of bytes to free (identical to size as passed to NASD_Malloc()). The results of calling NASD_Free() with a size that does not correspond to the size used to allocate that region of memory or calling NASD_Free() with a pointer that did not result from a call to NASD_Malloc() is undefined.

For instance, to allocate two kilobytes of memory, and later free it, one might use:

Note that this code assumes that nasd_mem_init() has already completed successfully, and that nasd_mem_shutdown() will be called later.

nasd_status_t
allocate_2k(
  char  **twok_bytes_ptr)
{
  char *bytes;

  NASD_Malloc(bytes, 2048, (char *));
  if (bytes == NULL) {
    printf("Could not get memory\n");
    return(NASD_NO_MEM);
  }

  *twok_bytes_ptr = bytes;
  return(NASD_SUCCESS);
}

void
deallocate_2k(
  char  *twok_bytes)
{
  NASD_Free(twok_bytes, 2048);
}


Debugging memory usage

If NASD_MEM_COUNT_ALLOC is defined nonzero in nasd_options.h, the memory module will provide the global symbol nasd_mem_allocated of type nasd_int64. This variable will, at any time, report the amount of memory currently "outstanding"; that is, memory allocated with NASD_Malloc() but not yet deallocated with NASD_Free(). It is not permissible to write this value. It is permissible to read it after calling nasd_mem_shutdown(). This value may be used as an indication of whether or not there is a core leak in the system. After all modules have been shut down, this value should be zero. If it is nonzero, something leaked from the core.

Of course, knowing that a core leak has occurred and knowing where it occurred are two different matters. While pinpointing the moment at which the reference to leaked memory was lost or identifying memory as simply allocated but never freed is beyond the scope of the memory module, it can identify where unfreed ranges of memory were allocated. When NASD_TRACK_ALLOCATIONS is defined nonzero in nasd_options.h, the memory module will remember the file and line number of each call to NASD_Malloc() for outstanding memory ranges, and can report this information. If NASD_TRACK_ALLOCATIONS is enabled, this will be done automatically when nasd_mem_shutdown() is called for the last time (that is, when the reference count on the memory module zeroes). This dump can also be triggered by calling nasd_mem_dump_unfreed(), which takes no arguments and returns nasd_status_t. Additionally, when NASD_TRACK_ALLOCATIONS is enabled, the memory subsystem will generate a warning any time NASD_Free() is called with a different size than resulted from the corresponding call to NASD_Malloc(), as well as warnings for calls to NASD_Free() with pointers that did not result from calls to NASD_Malloc(). Be aware that enabling NASD_TRACK_ALLOCATIONS causes both memory usage and the expense of memory operations to become inflated. It is recommended that this mode only be enabled when it is necessary to track down a particular bug.

One common mistake when programming is writing past the beginning or end of a chunk of allocated memory. If NASD_MEM_FENCEPOST is defined to a value greater than or equal to three, NASD_MEM_FENCEPOST unsigned longs will be prepended and appended to each buffer of allocated memory, and initialized with well-known garbage values (NASD_MEM_FENCEPOST_PATTERN). When the memory is freed, the memory module will determine if these values have been altered, and generate warnings if needed. Like NASD_TRACK_ALLOCATIONS, this operation causes both memory usage and the expense of memory operations to become inflated. It is therefore recommended that NASD_MEM_FENCEPOST only be enabled when necessary.

Uninitialized memory is the bane of many programmers, partly because it involves a degree of nondeterminism when attempting to reproduce bugs. The memory module can assist in identifying uninitialized memory by filling buffers resulting from calls to NASD_Malloc() with a well-known fill pattern. If NASD_MEM_FILL is defined nonzero in nasd_options.h, then the value it is defined to will be used as a 32-bit fill pattern for freshly-allocated memory. A popular value to set this to is 0xdeadbeef, because that places recognizable nonzero bits in all 32 positions, and this is not a valid pointer on most platforms.


<--- ---> ^<br>|<br>|
Thread groups Freelists NASD Programmer's Documentation