Chapter 4
Reference

This chapter provides details for each function in the SmartHeap library. Section 4.1 lists functions by category. Section 4.2 includes a detailed description and syntax of each SmartHeap function. Section 4.3 lists SmartHeap error codes and their meanings.

4.1 Functions by category

4.1.1 Task registration

4.1.2 Memory pools

4.1.3 ANSI standard C API

4.1.4 C++ API

4.1.5 Pointer-based API

4.1.6 Fixed-size API

4.1.7 Handle-based API

4.1.8 Error handling

4.1.9 Debugging

4.2 Function reference (alphabetical)

4.3 Error codes

4.1 Functions by category

This section lists SmartHeap functions by category and briefly describes their purpose. For a complete description of the syntax and use of each function, see §4.2.

4.1.1 Task registration

MemRegisterTask

Initializes the SmartHeap library.

MemUnregisterTask

Terminates the SmartHeap library.

SmartHeap automatically initializes itself on the first call to the library. Alternatively, you can explicitly initialize SmartHeap by calling MemRegisterTask.

MemUnregisterTask terminates SmartHeap, releasing all memory pools and internal data structures to the operating system. SmartHeap maintains a registration reference count, so MemUnregisterTask terminates SmartHeap only when it has been called as many times as MemRegisterTask has been called.

Important! In multi-threaded versions of SmartHeap, MemRegisterTask is required. If your application uses SmartHeap in multiple threads, the first thread must call MemRegisterTask before secondary threads make any SmartHeap calls. This requirement allows SmartHeap to complete initialization of synchronization objects before they’re used.

MemVersion

Returns the SmartHeap version number.

MemProcessSetGrowIncrement

Controls how much memory SmartHeap requests from the operating system when a memory pool needs to grow.

MemProcessSetFreeBytes

Controls how much free space SmartHeap maintains in the large block heap.

MemProcessSetLargeBlockThreshold

Controls the block size SmartHeap manages in its large block heap.

4.1.2 Memory pools

MemPoolAttachShared

Maps a shared memory pool into the current process.

MemPoolInit

Allocates and initializes a memory pool.

MemPoolInitFS

Allocates and initializes a memory pool, and pre-allocates specified count of fixed-size blocks.

MemPoolInitNamedShared

Allocates and initializes a memory pool that can be shared between processes.

MemPoolInitNamedSharedEx

Allocates and initializes a memory pool that can be shared between processes, with specified address and security attributes.

MemPoolInitRegion

Allocates and initializes a memory pool within a user-specified region of memory.

MemPoolFree

Returns all memory in a memory pool to the operating system in one fast operation.

MemPoolSetPageSize

Establishes the size of pages within which SmartHeap sub-allocates.

MemPoolSetBlockSizeFS

Establishes the size of blocks allocated from the pool with MemAllocFS.

MemPoolSetSmallBlockAllocator

Establishes or changes the small-block allocator algorithm for a given memory pool.

MemPoolSetSmallBlockSize

Establishes or changes the threshold below which allocation requests are routed to the small-block memory manager — allows small blocks to be allocated very quickly.

MemPoolSetFloor

Establishes or changes the minimum size to which SmartHeap will ever shrink the pool.

MemPoolSetCeiling

Establishes or changes the maximum size of a memory pool — SmartHeap won’t allow the pool to consume more system memory than the ceiling.

MemPoolPreAllocate

Reserves the specified number of bytes for future allocations from the memory pool.

MemPoolPreAllocateHandles

Reserves handle table entries for use with the handle-based allocation API.

MemPoolSetFreeBytes

Controls free space in a pool just as MemProcessSetFreeBytes controls free space in the large block heap.

MemPoolShrink

Reduces the size of a memory pool, returning memory not currently in use to the operating system.

MemPoolCount

Returns the net count of allocations from a memory pool.

MemPoolSize

Returns the total number of bytes of memory allocated within a memory pool.

MemPoolInfo

Obtains information about a memory pool.

MemPoolFirst

Begins enumeration of all SmartHeap memory pools.

MemPoolNext

Continues enumeration of all SmartHeap memory pools.

MemPoolCheck

Checks each entry in a memory pool for consistency.

MemPoolWalk

Traverses a memory pool, returning information about each entry in turn.

MemPoolSetSerialization

Toggles serialization.

Multi-threading MemPoolLock

Locks a pool for exclusive access by the calling thread.

Multi-threading MemPoolSetMaxSubpools

Controls how many sub-pools SmartHeap will create to avoid heap contention.

Multi-threading MemPoolUnlock

Unlocks a pool, relinquishing exclusive access by the calling thread.

Multi-threading MemPoolSetHighThreads

Sets space/contention tradeoff for a memory pool.

SmartHeap memory pools provide a mechanism for working with a set of related allocations. They establish a working set, occupying a minimal number of pages to satisfy the requested allocations. Related allocations thus tend to be swapped in or out of physical memory together, making memory accesses more efficient.

An entire memory pool can be freed in one operation, which eliminates the need to free each allocated block individually. Memory pools simplify your code and greatly reduce the incidence of common memory errors, such as double freeing or leakage (failing to free memory no longer in use). For example, you could allocate each element of a linked list from a memory pool and free the entire list by simply freeing the memory pool (you can free an individual element if you want to delete that element only).

Memory pools are implemented in SmartHeap by sub-allocation within pages that are a multiple of the system page size (see MemPoolSetPageSize). Each memory pool can contain both fixed- and variable-size blocks. In addition, each pool has a “small block threshold.” SmartHeap automatically routes blocks smaller than the pool’s small block threshold (see MemPoolSetSmallBlockSize) to the fixed-size allocator and routes larger blocks to the general purpose variable-size allocator.

If you use only ANSI C memory management APIs (malloc, etc.) or C++ operator new, you do not need to create a memory pool. In this case, a single, default memory pool is automatically allocated for each task or process that uses SmartHeap. To use any of the memory pool functions with the default memory pool, pass the value MemDefaultPool as the memory pool parameter.

Windows 16-bit In the 16-bit Windows version of SmartHeap, memory pools are either owned by the calling task or they’re allocated as shareable under the rules of Windows 3.x (GMEM_DDESHARE). Shared memory pools are owned by the module that creates them. Each Windows EXE and each DLL that uses SmartHeap has its own distinct default memory pool (even if they each use the SmartHeap DLL). In EXEs, the default memory pool is non-shared; for DLLs, it is shared memory.

4.1.3 ANSI standard C API

malloc

Allocates a block of uninitialized memory from the default memory pool.

calloc

Allocates a block of memory from the default memory pool, initializing its contents to zero.

realloc

Changes the size of a memory block.

free

Frees a block.

These functions are all defined by the ANSI standard for the C language. This API is therefore portable, and probably already familiar to you. Each of these functions allocates from the default memory pool (see §4.1.2 for details on memory pools).

You have two choices for using this API. You can replace the functions in your C runtime library by linking with the standard SmartHeap library (which redefines malloc, etc.). In this case you do not need to include any SmartHeap header files or recompile your application — just relink.

Alternatively, if you do not wish to replace the malloc function in your C runtime library, you can include the file shmalloc.h in each of your source files and remove the shmalloc object module from the SmartHeap library. This header file provides macro versions of malloc, etc. that are defined in terms of SmartHeap functions. This technique isn’t recommended unless there are specific conflicts between SmartHeap malloc and your C runtime library. If you use this technique, you must be very careful to include shmalloc.h in each module that calls one of the above functions.

Note that in order to capture file and line information in the debug version of SmartHeap, you must include shmalloc.h in each of your source modules regardless of whether you link in the SmartHeap malloc definition.

Note In the 16-bit x86 versions of SmartHeap, these functions are far functions and accept/return far memory pointers regardless of memory model, unlike their C runtime library counterparts. The large memory model is therefore required to replace the C runtime functions malloc, etc. The macro version of malloc works in all memory models, provided that any pointers storing the result of malloc are explicitly declared to be far pointers.

4.1.4 C++ API

new type

Allocates a memory block in C++ from default memory pool.

new (pool) type

Allocates a memory block in C++ from specified memory pool.

delete

Frees a memory block allocated with new.

set_new_handler

Establishes a C++ out-of-memory handler.

These functions are the standard mechanism for dynamic memory allocation in C++. Two overloaded versions of operator new are defined for allocations: one for allocating from the default memory pool (see §4.1.2 for details on memory pools) and one for allocating from the memory pool you specify (using the placement syntax for operator new). Both of these definitions provide a global operator new for general-purpose allocation.

The SmartHeap library replaces the new and delete operators defined by your C++ runtime library with SmartHeap’s definitions. If you use only standard global operators new and delete, you do not need to include SmartHeap header files or recompile — just relink to override new and delete. To use the SmartHeap-specific version of operator new (supplying a memory pool with the placement syntax), you must include the header file smrtheap.hpp.

To capture file and line information in the debug version of SmartHeap, you must include smrtheap.h in each of your source modules, even if you use only the standard global operator new.

A useful technique is to define operators new and delete for specific C++ classes using SmartHeap fixed-size memory pools (see the entry for new in §4.2, “Function reference,” for an example). This will ensure the most efficient and convenient dynamic memory allocation for C++ class objects.

Note In the 16-bit x86 versions of SmartHeap, these functions are far functions and accept/return far memory pointers regardless of memory model, unlike their C++ runtime library counterparts. The large memory model is therefore required to replace the standard global operators new and delete. In all memory models, you can use the SmartHeap operator new with the placement syntax, or you can define your own overloaded operator new for specific classes.

4.1.5 Pointer-based API

MemAllocPtr

Allocates a memory block for a specified memory pool and returns a pointer.

MemReAllocPtr

Changes the size of a memory block.

MemFreePtr

Frees a memory block.

MemSizePtr

Returns the size of a memory block.

MemCheckPtr

Validates a pointer.

MemAllocAligned

Allocate a block with a particular alignment.

These functions represent the most useful general-purpose API for management of variable-size memory blocks. The functions are similar to the ANSI C malloc, etc., except that they allocate from a memory pool you supply. You can therefore use these functions with several memory pools to gain better control of the working set of your application and tune different memory pools for different purposes (malloc always allocates from MemDefaultPool).

These functions are also more flexible than malloc — they accept an unsigned long size parameter rather than size_t and a flags parameter to control zero-initialization and other allocation attributes.

Use MemPoolInit to allocate memory pools for use with this API.

Note In cases where you’re allocating many objects of a small, fixed size (such as a linked list), the fixed-size API (see §4.1.6 for details on fixed-size API) may be preferable because it is faster, consumes less memory, and is fragmentation free.

4.1.6 Fixed-size API

MemAllocFS

Allocates a fixed-size block from a memory pool, returning a pointer.

MemFreeFS

Frees a memory block allocated by MemAllocFS.

These functions are ideal for allocating small fixed-size objects, such as linked lists elements, tree nodes, C structures, C++ class objects, and so on. This is the fastest memory allocation API. Fixed-size memory pools incur little or no per-allocation overhead and are fragmentation free, since all blocks are of equal size.

To allocate memory pools for use with this API, use MemPoolInitFS, or use MemPoolInit in conjunction with MemPoolSetBlockSizeFS.

You can use a single function call to free all of the objects that were allocated from a pool. This is much faster and less error prone than freeing each object individually. For example, you could set up a fixed-size memory pool for a linked list with MemPoolInitFS, allocate each element with MemAllocFS, then later free the entire linked list by calling MemPoolFree.

4.1.7 Handle-based API

MemAlloc

Allocates a memory block, returning a handle.

MemReAlloc

Changes the size of a memory block allocated with MemAlloc or MemReAlloc.

MemFree

Frees a memory block allocated by MemAlloc or MemReAlloc.

MemLock

Increments the lock count of a moveable memory block, which prevents the block from being moved.

MemUnlock

Decrements a block’s lock count if previously locked with MemLock; the block can move when the lock count becomes zero.

MemFix

Increments a block’s fix count, moving the block to the fixed heap to avoid fragmenting the moveable heap.

MemUnfix

Decrements a block’s fix count, moving it back to moveable heap if fix count is zero.

MEM_REFERENCE

Macro that dereferences the memory that is identified by a given handle without locking the handle — implemented as a simple indirection in non-debug SmartHeap.

MemHandle

Retrieves the handle of the memory block at the specified address (previously returned by MemLock or MemFix).

MemIsMoveable

Determines whether a block is on the fixed or the moveable heap.

MemLockCount

Retrieves the lock or fix count of a memory block.

MemSize

Returns the actual size of a memory block.

MemSizeRequested

Returns the requested size of a memory block.

The handle-based API provides a moveable memory heap implementation, somewhat like moveable memory provided by the Windows API or relocatable memory provided by the Mac.

The SmartHeap handle-based implementation maintains dual heaps in each memory pool — one for fixed blocks and one for moveable blocks. This permits the moveable heap to be fluid and completely fragmentation-free as long as all blocks within it are unlocked. Moveable memory can be referenced at any time with the MEM_REFERENCE macro, even if the block is currently unlocked.

The MemLock function lets you retain a reference to a block until a matching MemUnlock is called. If you intend to lock a block for an extended period, MemFix is recommended. This copies the block to the fixed heap where it will not cause a “sandbar” in the moveable heap, as locked moveable blocks do. MemUnfix moves the block back to the moveable heap. Both MemLock and MemFix maintain reference counts so that nested locks and fixes will work correctly.

Note In general, the ANSI, pointer-based, or fixed-size APIs are preferable to the handle-based API, because it is much easier to deal with direct pointers to memory. The former three methods are also faster, because locking and memory movement are not occurring.

The handle-based API is suitable when you allocate several medium to large variable-size blocks from a pool, and you do not allocate any small blocks that would fill in the spaces between them. This API is also suitable when you have a large block, such as an array, that is repeatedly reallocated to a larger size. If you were to use a non-moveable memory allocator for such cases, a significant amount of memory would be lost to fragmentation.

4.1.8 Error handling

MemDefaultErrorHandler

The default error-handling function that will be in effect if you don’t implement your own.

MemSetErrorHandler

Establishes or changes the memory error-handling callback function for the current task or process.

MemErrorUnwind

You must call this function before a non-local exit (longjmp) from your custom memory error handler.

These functions are used for detecting and handling runtime error conditions, such as running out of memory, parameter errors, or double freeing.

The error handler can either cause a non-local exit (for example, longjmp), or attempt recovery (for example, free some memory and retry an allocation that has failed).

The error handler acts much like the new_handler of C++, except the SmartHeap error handler handles many error conditions aside from running out of memory. It also lets you retry on recoverable errors. If you carefully define an error handler, you can avoid testing the result of every call to an allocation function. This makes programming more convenient, reduces the chances for programming error, and produces more efficient and more readable code.

Note You can establish an error handler even if you use the ANSI allocators exclusively. Therefore, even without modifying existing source code (containing calls to malloc or new), you can greatly improve the robustness of your application.

In the debug version of SmartHeap, the error handler is invoked with detailed information on the error, including the type of error, the address of a corruption, and even the source file/line and parameters of the call where the error was detected.

4.1.9 Debugging

dbgMemCheckPtr

Validates a memory address. Capable of checking both heap and non-heap pointers.

dbgMemCheckAll

Validates all memory pools in the current process.

dbgMemSetSafetyLevel

Establishes or changes the level of error checking for the current task or process.

dbgMemSetGuardSize

Establishes the number of guard bytes to pad before and after each allocation, to detect overwrites.

dbgMemSetGuardFill

Establishes the character with which to fill guard bytes.

dbgMemSetFreeFill

Establishes the character with which to fill free blocks.

dbgMemSetInUseFill

Establishes the character with which to fill allocated blocks.

dbgMemSetCheckpoint

Establishes the context for allocations — useful for tracking down overwrites and leakage.

dbgMemSetCheckFrequency

Establishes how frequently, by default, memory pools are checked for overwrites.

dbgMemPoolSetCheckFrequency

Establishes how frequently the memory pool is checked for overwrites.

Multi-threading dbgMemScheduleChecking

Schedules checking of all memory pools in a background thread.

dbgMemDeferFreeing

Causes free blocks in all memory pools to be marked free rather than actually freed, to detect writes into free blocks.

dbgMemPoolDeferFreeing

Causes free blocks in the specified memory pool to be marked free rather than actually freed, to detect writes into free blocks.

dbgMemSetDeferSizeThreshold

Establishes the maximum size of blocks that are placed on the queue of defer-freed allocations.

dbgMemSetDeferQueueLen

Establishes the maximum number of blocks that are placed on the queue of defer-freed allocations (default for all memory pools).

dbgMemPoolSetDeferQueueLen

Establishes the maximum number of blocks that are placed on a particular pool’s queue of defer-freed allocations.

dbgMemFreeDeferred

Actually frees any blocks in all memory pools that were freed when “defer freeing” was in effect.

dbgMemPoolFreeDeferred

Actually frees any blocks in the specified memory pool that were freed when “defer freeing” was in effect.

dbgMemProtectPtr

Marks a memory block as read-only, no-free, and/or no-realloc. Any attempt to modify, free, or realloc (respectively) the block will be reported as an error.

dbgMemPoolSetName

Assigns a name to a memory pool, to facilitate identification of the pool in error reports.

dbgMemReallocMoves

Toggles a setting that causes Debug SmartHeap to always move blocks resized with realloc.

dbgMemSuppressFreeFill

Toggles a setting that controls whether Debug SmartHeap fills free blocks with a unique signature.

Windows 16-bit dbgMemReportWrongTask

Toggles a setting that causes Debug SmartHeap to report references to private memory from a task that does not own the memory.

dbgMemPtrInfo

Retrieves information about the specified allocation, including its size and where it was allocated.

dbgMemPoolInfo

Retrieves information about the specified memory pool, including its debugging settings and where it was created.

dbgMemSettingsInfo

Retrieves global Debug SmartHeap debugging settings.

dbgMemFormatErrorInfo

Formats to a string an error record that was reported to a SmartHeap error handler.

dbgMemFormatCall

Formats to a string an API that was reported to a SmartHeap error handler.

dbgMemSetDefaultErrorOutput

Establishes the output destination for the default SmartHeap error reporting mechanism (errors can be directed to any combination of interactive prompt, file, or debugging console).

dbgMemSetEntryHandler

Establishes a hook that is called at each SmartHeap entry point.

dbgMemSetExitHandler

Establishes a hook that is called at each SmartHeap exit point.

dbgMemBreakpoint

Invokes the SmartHeap error handler with an error of type MEM_BREAKPOINT.

dbgMemReportLeakage

Reports blocks that have not been freed between the specified checkpoints.

The above functions are present only in the Debug version of SmartHeap. These debug functions are used to detect bugs in your program before an error actually displays symptoms and to isolate the cause of errors post-mortem.

When using debug SmartHeap functions, you must define the preprocessor manifest constant MEM_DEBUG before you include smrtheap.h; otherwise, each of the above functions is defined as an empty macro (that is, a no-op). The runtime version of SmartHeap turns debug functions into macros, which lets you have debugging calls throughout your application source code without the need for #ifdef statements.

See Chapter 3, “Debugging,” for a detailed description of Debug SmartHeap.

4.2 Function reference

This section describes each of the SmartHeap functions in alphabetical order. If you’re looking for a function in a particular functional category but you don’t know its name, see §4.1.

Descriptions for each function follow the format illustrated here:

A brief, one-sentence description of the function.

Syntax The declaration syntax for the function. All C or C++ syntax is shown in courier.

Return value The value returned by the function.

Description A detailed description of the function’s parameters, behavior, and effects.

Comments Special considerations for the function, including platform-specific issues, usage suggestions, and performance tips.

Errors Error conditions that can arise in a call to the function. See §4.3, “Error codes,” for the meaning of each error code and the safety level needed to detect the error.

See also Related routines that might be of interest.

Example /* A code sample using the function. */

calloc

ANSI C standard zero-initializing allocator for an array of nobj elements, each of size size.

Syntax #include <shmalloc.h> macro or debug version, or
#include <stdlib.h> ANSI C function version

void *calloc(size_t nobj, size_t size);

Return value Returns a pointer to the allocated space. The return value is NULL if there is insufficient memory.

Description The calloc function allocates a block nobj x size bytes in size and initializes each bit in the block to zero.

calloc allocates from the default memory pool implicitly defined by SmartHeap for the task or process from which you call calloc. If you wish to call a memory pool function with the pool used by calloc (for example, MemPoolSize, MemPoolShrink, MemPoolCount), supply the value of the global variable MemDefaultPool for the memory pool parameter.

If nobj or size is zero, calloc returns a pointer to zero bytes of memory.

The maximum size of a single block that can be allocated with calloc is UINT_MAX minus approximately 24 bytes. Use MemAllocPtr for larger blocks on 16-bit platforms.

Comments The SmartHeap library defines the calloc function, overriding the definition present in your C runtime library. You must specify the SmartHeap library to your linker before you specify your C runtime library to ensure that you get SmartHeap’s function rather than the compiler’s function. If for some reason you do not want to override your compiler’s calloc function, you must remove the shmalloc object module from the SmartHeap library (see §2.3.3 for instructions). In this case, you can still have calloc calls go to SmartHeap by including shmalloc.h in each of your source modules — this header file defines calloc as a macro rather than as a function.

In 16-bit x86 versions of SmartHeap, calloc is a far function returning a far pointer regardless of memory model. Therefore, you must either use the large memory model or else use the macro version of calloc as described above. SmartHeap also overrides either _fcalloc or farcalloc for compilers that define one of these functions.

Errors Error code Caused by

MEM_ALLOC_ZERO Either size or nobj is zero.

MEM_BLOCK_TOO_BIG The product of nobj and size exceeds UINT_MAX - 24.

MEM_EXCEEDED_CEILING Total size of allocations in the default memory pool exceeds the size specified by MemPoolSetCeiling.

MEM_OUT_OF_MEMORY There is insufficient operating system memory to satisfy the allocation request.

See also free, malloc, MemAlloc, MemAllocFS, MemAllocPtr, MemSizePtr, new, realloc

Example #include <shmalloc.h>

typedef struct
{
char *str;
int len;
} string;

string *InitStringTable(int num_elts)
{
return (string *)
calloc(num_elts, sizeof(string));
}

dbgMemBreakpoint

Triggers a breakpoint and invokes the SmartHeap error handler.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

void dbgMemBreakpoint(void);

Return value None

Description Use dbgMemBreakpoint to stop execution at strategic points in your application. When Debug SmartHeap stops at the breakpoint, the error handler is called. If you have not installed an error handler, the breakpoint is signaled via the output specified by MemDefaultErrorOutput.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemSetEntryHandler, dbgMemSetExitHandler

Errors None

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* free a data structure, then trigger a breakpoint
* so we can browse allocations to determine if all
* the pieces of the data structure have been freed
*/
typedef struct _Tree
{
struct _Tree *left;
struct _Tree *right;
char *value;
} Tree;

void freeTree(Tree *tree, Tree *root)
{
if (tree)
{
/* recursively free branches of tree */
freeTree(tree->left, root);
freeTree(tree->right, root);

/* and free this tree element */
free(tree->value);
free(tree);
}

if (tree == root)
/* entire tree has been freed: stop */
dbgMemBreakpoint();
}

dbgMemCheckAll

Checks the entire heap for overwrites.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemCheckAll(void);

Return value Returns non-zero if all heap memory is free of overwrites, otherwise zero.

Description dbgMemCheckAll reports overwrites of heap memory to the current error handler.

This function checks all memory pools for overwrites. You can use MemPoolCheck to check an individual memory pool.

An overwrite is a write to a memory location that isn’t currently allocated to the data structure that you’re updating.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

Errors Error code Caused by

MEM_BAD_BLOCK An overwrite over an internal heap data structure was detected.

MEM_BAD_FREE_BLOCK An overwrite over an internal header of free heap memory was detected.

MEM_FREE_BLOCK_WRITE An overwrite into free memory was detected.

MEM_OVERWRITE An overwrite after the end of an allocation was detected.

MEM_READONLY_MODIFIED An allocation marked read-only was modified.

MEM_UNDERWRITE An overwrite before the beginning of an allocation was detected.

See also dbgMemCheckPtr

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* check on entry and exit of a buggy routine:
* if overwrites are reported on exit but not
* on entry, the overwrite has been narrowed to
* this routine
*/
void buggy()
{
dbgMemCheckAll();

...

dbgMemCheckAll();
}

dbgMemCheckPtr

Determines whether a pointer is a valid memory address.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemCheckPtr(void *ptr,
MEM_POINTER_TYPE type, unsigned long size);

Return value dbgMemCheckPtr returns non-zero if the pointer is valid, otherwise zero.

Description dbgMemCheckPtr determines whether ptr is a valid address of type type, at which at least size bytes of memory are addressable. To determine whether a pointer has read or write access regardless of what type of memory it points to, specify type MEM_POINTER_READONLY or MEM_POINTER_READWRITE, respectively.

If you specify type MEM_POINTER_HEAP, the function returns non-zero if the value you supply for ptr is the result of any memory allocation function except the SmartHeap MemAlloc API. SmartHeap returns an error if the pointer doesn’t point to a valid heap allocation.

To validate a function pointer, specify type MEM_POINTER_CODE.

Note You can use this function to isolate dangling or wild pointers when you’re debugging your application. It is also useful for performing parameter validation within your application’s own internal APIs.

MEM_POINTER_TYPE is defined as:

typedef enum
{
MEM_POINTER_HEAP,
MEM_POINTER_CODE,
MEM_POINTER_READONLY,
MEM_POINTER_READWRITE
} MEM_POINTER_TYPE;

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

Errors Error code Caused by

MEM_BAD_POINTER ptr does not point to heap memory.

MEM_DOUBLE_FREE ptr points to a previously freed heap allocation.

MEM_WRONG_TASK ptr points to non-shared memory not owned by the current task.

See also dbgMemCheckAll, dbgMemWalkHeap, dbgMemProtectPtr

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* example list link structure */
struct Link
{
int value;
struct Link *next;
};

/* check all links in a list for validity */
int CheckList(struct Link *link)
{
/* traverse list, returning
immediately on error */
while (link)
if (dbgMemCheckPtr(link, MEM_POINTER_HEAP,
sizeof(struct Link)))
link = link->next;
else
return FALSE;

return TRUE;
}

dbgMemDeferFreeing

Turns deferred freeing on or off.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemDeferFreeing(MEM_BOOL bDefer);

Return value Returns non-zero if successful, otherwise zero.

Description dbgMemDeferFreeing sets or clears the default deferred freeing setting. If bDefer is non-zero, freed allocations are filled with the free fill value. However, instead of returning these allocations to the free pool for reuse, SmartHeap adds them to the queue of defer-freed allocations. Defer-freed allocations remain in the queue until you free them explicitly using dbgMemFreeDeferred or until the queue fills up and the oldest allocations in the queue are freed automatically. To change the length of the queue, use dbgMemSetDeferQueueLen.

If you turn deferred freeing off, references to free memory may not be caught because free memory will immediately be recycled for subsequent allocations.

SmartHeap is more likely to detect references to free memory if deferred freeing is on but will use less memory if deferred freeing is off. This function sets the default deferred-freeing setting for all pools. To turn deferred freeing on or off for a particular pool, use dbgMemPoolDeferFreeing.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemFreeDeferred, dbgMemSetDeferQueueLen, dbgMemSetDeferSizeThreshold, dbgMemPoolDeferFreeing

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* extend deferral of freeing to catch
* references to free memory
*/
void detectFreeRefs()
{
/* turn deferred freeing on */
dbgMemDeferFreeing(TRUE);

/* set defer queue length to 10,000 allocations */
dbgMemSetDeferQueueLen(10000);

/* set maximum size of allocation to defer
freeing of to 100,000 bytes */
dbgMemSetDeferSizeThreshold(100000ul);
}

dbgMemFormatCall

Formats the API and parameters reported to an error handler.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

unsigned dbgMemFormatCall(
MEM_ERROR_INFO *errorInfo, char *buf,
unsigned bufsize);

Return value Returns the number of bytes actually output to buf.

Description dbgMemFormatCall formats the function name and parameters specified by the fields of errorInfo. See MemSetErrorHandler for details on the MEM_ERROR_INFO structure.

Output from this function is copied to buf. No more than bufsize characters are placed into buf — bufsize must specify the size of buf.

Important! You should only call this function from an error handler established by MemSetErrorHandler. SmartHeap calls the error handler with a pointer to a MEM_ERROR_INFO structure. Pass this value as the errorInfo parameter to dbgMemFormatCall.

Comments This function is called by dbgMemFormatErrorInfo to format the API where an error is detected and where a corrupted object was created. You can use this function to customize error formatting, but avoid parsing the parameter fields of MEM_ERROR_INFO, which differ for each SmartHeap API.

This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to zero. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemFormatErrorInfo, MemSetErrorHandler, MemDefaultErrorHandler, dbgMemSetDefaultErrorOutput

Example #define MEM_DEBUG 1
#include <smrtheap.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_CALL 256
/* example SmartHeap error handler that calls
dbgMemFormatCall to customize error output
*/
MEM_BOOL MEM_CALLBACK MyErrorHandler(
MEM_ERROR_INFO *errorInfo)
{
char buf[MAX_CALL+1];

fputs("Memory error detected in: ", stderr);
dbgMemFormatCall(errorInfo, buf, MAX_CALL);
fputs(buf, stderr);

abort();
return 0;
}

dbgMemFormatErrorInfo

Formats the error information reported to an error handler.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

unsigned dbgMemFormatErrorInfo(
MEM_ERROR_INFO *errorInfo, char *buf,
unsigned bufsize);

Return value Returns the number of bytes actually output to buf.

Description dbgMemFormatErrorInfo formats information specified by the fields of errorInfo. This information includes the API and location where an error was detected, the API and location where a corrupted object was created, and the address and contents of the corrupted object. For details on the MEM_ERROR_INFO structure, see MemSetErrorHandler.

Output from this function is copied to buf. No more than bufsize characters are placed into buf — bufsize must specify the size of buf.

Important! You should only call this function from an error handler established by MemSetErrorHandler. SmartHeap calls the error handler with a pointer to a MEM_ERROR_INFO structure. Pass this value as the errorInfo parameter to dbgMemFormatErrorInfo.

Comments You can use this function to customize error input/output, but avoid parsing and formatting the fields of MEM_ERROR_INFO.

This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to zero. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemFormatCall, MemSetErrorHandler, MemDefaultErrorHandler, dbgMemSetDefaultErrorOutput

Example #define MEM_DEBUG 1
#include <smrtheap.h>
#include <stdio.h>
#include <stdlib.h>

#define MAX_OUT 800
/* example SmartHeap error handler that calls
dbgMemFormatErrorInfo to customize I/O
*/
MEM_BOOL MEM_CALLBACK MyErrorHandler(
MEM_ERROR_INFO *errInfo)
{
char buf[MAX_OUT+1];

fputs("Fatal Memory Error!\n", stderr);
dbgMemFormatErrorInfo(errInfo,buf, MAX_OUT);
fputs(buf, stderr);

abort();
return 0;
}

dbgMemFreeDeferred

Frees all allocations in the queue of defer-freed allocations in all memory pools.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemFreeDeferred(void);

Return value Returns non-zero if successful, otherwise zero.

Description dbgMemFreeDeferred deallocates any allocations, in all memory pools, that were marked as free while deferred freeing was in effect. Use dbgMemDeferFreeing to control the current deferred freeing status. You can call this function whether or not deferred freeing is currently in effect.

Note Use this function to reclaim memory whose freeing was previously deferred. You might call this function in response to detecting a low-memory condition. You might also call it after safely exiting an area of code where you suspect overwrites.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemDeferFreeing, dbgMemPoolFreeDeferred

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* reclaim memory from the queue of defer-freed
* allocations, in response to an out-of-memory
* condition
*/
MEM_BOOL MEM_CALLBACK MyErrorHandler(
MEM_ERROR_INFO *errorInfo)
{
/* first call default error handler */
MEM_BOOL bRetry =
MemDefaultErrorHandler(errorInfo);

/* check for out-of-memory condition */
if (errorInfo->errorCode == MEM_OUT_OF_MEMORY)
{
/* free memory from defer-freed allocations
so that the current allocation can succeed */
dbgMemFreeDeferred();
}

return bRetry;
}

/* establish the above error handler as follows */
main()
{
MemSetErrorHandler(MyErrorHandler);

...
}

dbgMemPoolDeferFreeing

Controls delayed freeing of blocks in a memory pool.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemPoolDeferFreeing(MEM_POOL pool,
MEM_BOOL bDefer);

Return value Returns non-zero if pool is valid, otherwise zero.

Description dbgMemPoolDeferFreeing sets or clears deferred freeing for pool. If bDefer is:

When deferred freeing is on, freed allocations are filled with the free fill value. However, instead of returning these allocations to the free pool for reuse, Debug SmartHeap adds them to the queue of defer-freed allocations for pool. Defer-freed allocations remain in the queue until you free them explicitly using dbgMemPoolFreeDeferred or until the queue fills up and the oldest allocations in the queue are freed automatically. To change the length of the queue, use dbgMemPoolSetDeferQueueLen.

When deferred freeing is turned off, subsequent deallocations are freed normally.

This function affects the behavior of free, operator delete, MemFreePtr, MemFree, and MemFreeFS. Any blocks that are freed while a pool is in deferred freeing mode remain unfreed until you call dbgMemFreeDeferred.

Caution! Be aware that you can quickly exhaust available memory if you leave a pool in deferred freeing mode for an extended period. You should generally use this function only when actively debugging a specific problem.

Comments You can use this function to diagnose memory overwrites. If you write into a memory block after freeing it, the block may be in use elsewhere in your application, making detection of the overwrite very difficult. By turning deferred freeing on before such an overwrite, you guarantee that SmartHeap will detect the overwrite when it next checks the pool. Set the safety level to MEM_SAFETY_DEBUG to enable automatic overwrite checking (see example below).

Another use for this function is to force your application into a low-memory condition as a stress test. This is a platform-independent technique for gradually consuming all of available memory.

This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

See also dbgMemFreeDeferred, dbgMemProtectPtr, MemPoolCheck, dbgMemPoolSetCheckFrequency, dbgMemSetGuardSize, dbgMemSetGuardFill, dbgMemSetFreeFill, dbgMemSetInUseFill

Example #define MEM_DEBUG 1
#include <smrtheap.h>
#define TRUE 1

/* make appropriate SmartHeap calls to
prepare for maximum overwrite detection
*/
void DetectOverwrites(MEM_POOL pool)
{
/* turn on auto pool checking */
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);

/* check pool on every call to SmartHeap */
dbgMemPoolSetCheckFrequency(pool, 1);

/* detect writes into free blocks */
dbgMemPoolDeferFreeing(pool, TRUE);
}

dbgMemPoolFreeDeferred

Frees any blocks in a memory pool for which freeing was deferred.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemPoolFreeDeferred(MEM_POOL pool);

Return value Returns non-zero if pool is valid and contains no corrupt entries, otherwise zero.

Description dbgMemPoolFreeDeferred deallocates any blocks that were marked as free while deferred freeing was enabled in pool. Use dbgMemPoolDeferFreeing to control a pool’s deferred freeing status. You can call this function whether or not deferred freeing is currently in effect.

Comments Use this function to reclaim memory whose freeing was previously deferred. You might call this function in response to detecting a low-memory condition. You might also call it after safely exiting an area of code where you suspect overwrites.

This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

See also dbgMemDeferFreeing

Example #define MEM_DEBUG 1
#include <smrtheap.h>
#define TRUE 1
#define FALSE 0

/* wrap a suspicious area of code with
extra overwrite detection, then reclaim
any defer-freed memory after safely
exiting the suspect code
*/
void CallSuspectCode(MEM_POOL pool)
{
/* crank up safety */
MEM_SAFETY_LEVEL savedSafety =
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);

/* check pool on every call to SmartHeap */
dbgMemPoolSetCheckFrequency(pool, 1);

/* detect writes into free blocks */
dbgMemPoolDeferFreeing(pool, TRUE);

/* ... suspect code is here ... */

/* we got through it: back to normal */
dbgMemPoolDeferFreeing(pool, FALSE);
dbgSetSafetyLevel(savedSafety);

/* release any defer-freed memory */
dbgMemPoolFreeDeferred(pool);
}

dbgMemPoolInfo

Returns the current debugging settings associated with a memory pool.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemPoolInfo(MEM_POOL pool,
DBGMEM_POOL_INFO *poolInfo);

Return value Returns non-zero if pool and poolInfo are valid, otherwise zero.

Description dbgMemPoolInfo returns the current debugging settings associated pool.

The DBGMEM_POOL_INFO structure is defined as follows:

typedef struct {
MEM_POOL pool;
const char *name;
MEM_API createAPI;
const char *createFile;
int createLine;
unsigned long createPass;
unsigned long createAllocCount;
unsigned createCheckpoint;
int isDeferFreeing;
unsigned long deferQueueLength;
unsigned checkFrequency;
MEM_ERROR_INFO lastOkInfo;
unsigned long threadID;
unsigned long pid;
} DBGMEM_POOL_INFO;

The name field identifies the pool name established by dbgMemPoolSetName.

The createAPI field identifies the call (MemPoolInit or MemPoolInitFS) that created the pool. createFile, createLine, and createPass identify the source file location of that call. These fields will be zero if that source file was not compiled for Debug SmartHeap (that is, MEM_DEBUG defined), as described in Chapter 3, “Debug SmartHeap.”

createAllocCount and createCheckpoint indicate the allocation sequence number and checkpoint values at the time the pool was created.

The isDeferFreeing, deferQueueLength, and checkFrequency fields contain the value established by dbgMemPoolDeferFreeing, dbgMemPoolSetDeferQueueLen, and dbgMemPoolSetCheckFrequency, respectively.

The lastOkInfo field contains information about the most recent heap-related call that verified that the pool is free of overwrites. If SmartHeap reports an overwrite in a memory pool, you can use this information to diagnose where the overwrite occurred.. For details on the MEM_ERROR_INFO type, see MemSetErrorHandler.

The threadID and pid fields identify the thread and process where the pool was created. threadID is zero on non multi-threaded platforms. pid is zero on platforms that don’t support SmartHeap shared memory.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

Errors Error code Caused by

MEM_BAD_BUFFER poolInfo is invalid.

MEM_BAD_MEM_POOL pool is invalid.

See also dbgMemPoolDeferFreeing, dbgMemPoolSetCheckFrequency, dbgMemPoolSetDeferQueueLen, dbgMemPoolSetName, dbgMemSetCheckpoint, MemSetErrorHandler

Example #define MEM_DEBUG 1
#include <smrtheap.h>

const char *getPoolName(MEM_POOL pool)
{
DBGMEM_POOL_INFO poolInfo;

if (dbgMemPoolInfo(pool, poolInfo))
return poolInfo.name;
else
return NULL;
}

dbgMemPoolSetCheckFrequency

Establishes the frequency of memory pool auto-validation.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>
unsigned dbgMemPoolSetCheckFrequency(
MEM_POOL pool, unsigned freq);

Return value Returns the previous check frequency for pool if pool is valid, zero if no check frequency was established for the pool, or UINT_MAX if pool is invalid.

Description dbgMemPoolSetCheckFrequency determines how often SmartHeap performs heap checking. If the current safety level is MEM_SAFETY_DEBUG, SmartHeap will validate all of the entries of pool at every freq call to the library.

If you do not call dbgMemPoolSetCheckFrequency, or if you specify zero for freq, the check frequency for the pool assumes the global default established by dbgMemSetCheckFrequency.

The default check frequency is ten. That is, pool is fully validated on every tenth call to SmartHeap that involves pool (meaning that pool, or a memory block owned by pool, is a parameter in the SmartHeap call).

The maximum check frequency is UINT_MAX - 1.

Pool validation is done by an internal call to MemPoolCheck, which validates all entries in the pool whether currently in use or free. Every byte of each free block is checked for the free fill value. Every in-use block is checked for leading and trailing guards. All internal data structures in the pool are validated.

Comments Use this function to control the speed vs. safety tradeoff at a fine granularity. MEM_SAFETY_DEBUG slows down allocation speed considerably — especially for large memory pools. You can mitigate this by setting a high check frequency so validation occurs less frequently. Remember, the higher the value, the less frequent the checks. If check frequency is 2, the pool is validated every other call to a SmartHeap function; if check frequency is 20, the pool is validated every 20th call.

If some areas of your application are more suspect than others (for example, recently changed code vs. old, stable code), you can dynamically adjust the check frequency for different regions of code.

This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

See also dbgMemDeferFreeing, MemPoolCheck, dbgMemSetSafetyLevel

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* adjust check frequency according to the
stability of various portions of code */
void CodeUnderDevelopment(MEM_POOL pool)
{
/* crank up safety */
MEM_SAFETY_LEVEL savedSafety =
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);

/* fn1 was just written -- check pool
on every call to SmartHeap */
dbgMemPoolSetCheckFrequency(pool, 1);
fn1(...);

/* fn2 is very stable -- infrequent
checking is fine here */
dbgMemPoolSetCheckFrequency(pool, 100);
fn2(...);

/* restore safety level */
dbgSetSafetyLevel(savedSafety);
}

dbgMemPoolSetDeferQueueLen

Sets the number of defer-freed allocations that Debug SmartHeap retains in the queue for a specified memory pool.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

unsigned long dbgMemPoolSetDeferQueueLen(
MEM_POOL pool, unsigned long queueLength);

Return value Returns pool’s previous queue length if a queue length was established for pool, zero if no queue length was established for pool, or MEM_ERROR_RET if pool is invalid.

Description When deferred freeing is on, freed allocations aren’t actually freed, they’re placed in a queue. When the number of defer-freed allocations reaches queueLength, the oldest allocation in the queue is returned to the free pool for reuse.

Use dbgMemPoolSetDeferQueueLen to set the queue length for a particular pool. If you don’t call this function for a given pool, or if you specify zero for queueLength, the queue length for that pool assumes the global default established by dbgMemSetDeferQueueLen. The default queue length is 1000 allocations, and the maximum is ULONG_MAX - 1.

Note If you call dbgMemPoolSetDeferQueueLen and specify a smaller queue than the one currently in effect, the queue doesn’t shrink immediately. The queue shrinks the next time the application frees an allocation while deferred freeing is turned on.

Also note If you call dbgMemPoolSetDeferQueueLen and set a very large queue length, you can force your application into a low-memory condition as a stress test.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

See also dbgMemDeferFreeing, dbgMemSetDeferQueueLen

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* make appropriate Debug SmartHeap calls to
* prepare for increased overwrite detection
* for a given pool
*/
void DetectOverwrites(MEM_POOL pool)
{
/* turn on auto pool checking */
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);

/* check pool on every heap-related call */
dbgMemPoolSetCheckFrequency(pool, 1);

/* defer freeing for the pool */
dbgMemPoolDeferFreeing(pool, 1);

/* make the defer-freeing queue very long */
dbgMemPoolSetDeferQueueLen(pool, 10000);
}

dbgMemPoolSetName

Assigns a descriptive name to a memory pool to make it easier to identify the pool in Debug SmartHeap error reports.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemPoolSetName(MEM_POOL pool,
const char *name);

Return value Returns non-zero if pool and name are valid, otherwise zero.

Description Allocations created by calls to malloc or new are automatically added to the default pool, named "Default". If you don’t name pools you create, they are given generic names like "pool1", "pool2", and so on. To make these pools easier to identify in Debug SmartHeap error reports, you should call dbgMemPoolSetName right after you call MemPoolInit or MemPoolInitFS.

The maximum length of a name is 31 characters.

Errors Error code Caused by

MEM_BAD_BUFFER name is invalid.

MEM_BAD_MEM_POOL pool is invalid.

See also dbgMemPoolInfo

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* example list link structure */
typedef struct Link
{
int value;
struct Link *next;
};

/* create a memory pool to store
* list links, and name it appropriately
*/
MEM_POOL createLinkPool(unsigned count)
{
/* create pool */
MEM_POOL pool = MemPoolInitFS(sizeof(struct Link),
count, 0);

/* and name it */
if (pool)
dbgMemPoolSetName(pool, "Links");

return pool;
}

dbgMemProtectPtr

Controls the modifiability of a memory block.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemProtectPtr(void *ptr,
unsigned flags);

Return value Returns non-zero if ptr is a valid memory block, otherwise zero.

Description dbgMemProtectPtr sets protection flags for an individual memory block. The function controls whether the block pointed to by ptr can be modified, freed, and/or reallocated.

To construct the flags parameter, bitwise OR one or more of the following values:

DBGMEM_PTR_READONLY

The contents of the block can’t change.

DBGMEM_PTR_NOFREE

The block can’t be freed.

DBGMEM_PTR_NOREALLOC

The size of the block can’t be changed.

If you specify DBGMEM_PTR_READONLY, a checkpoint is maintained with the block. Each time the block or the memory pool is checked, the block’s checksum is validated. If the block has changed, SmartHeap reports MEM_READONLY_MODIFIED to the current error-handling routine.

If you specify DBGMEM_PTR_NOFREE, SmartHeap reports the error MEM_NOFREE if the protected block is passed as a parameter to free, delete, MemFreePtr, or MemFreeFS.

If you specify DBGMEM_PTR_NOREALLOC, SmartHeap reports the error MEM_NOREALLOC if the protected block is passed as a parameter to realloc or MemReAllocPtr.

To turn off protection previously set for a block, call dbgMemProtectPtr again, and specify zero or DBGMEM_PTR_NOPROTECTION for flags.

Comments You can use the DBGMEM_PTR_READONLY flag to diagnose one of the most mysterious forms of memory overwrite — a write into a wild or previously freed pointer that happens to be in use elsewhere in your application. Call dbgMemProtectPtr before the overwrite occurs, and SmartHeap will tell you when the contents change.

Sometimes a write into a previously-freed block occurs because the block was unexpectedly freed from an unknown place. You can use DBGMEM_PTR_NOFREE and DBGMEM_PTR_NOREALLOC to notify you of exactly where the memory is being freed.

This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

Errors Error code Caused by

MEM_BAD_POINTER ptr is invalid.

See also dbgMemPoolDeferFreeing, MemPoolCheck, MemCheckPtr, dbgMemPoolSetCheckFrequency

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* protect block against any changes */
void ConstifyPtr(void *ptr)
{
dbgMemProtectPtr(ptr, DBGMEM_PTR_READONLY |
DBGMEM_PTR_NOFREE | DBGMEM_PTR_NOREALLOC);
}

dbgMemPtrInfo

Returns the current debugging settings associated with an allocation.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemPtrInfo(void *ptr,
DBGMEM_PTR_INFO *ptrInfo);

Return value Non-zero if ptr is valid, otherwise zero.

Description Returns information about an allocation. The DBGMEM_PTR_INFO structure is defined as follows:

typedef struct {
void *ptr;
MEM_POOL pool;
unsigned long argSize;
MEM_BLOCK_TYPE blockType;
MEM_BOOL isInUse;
MEM_API createAPI;
const char *createFile;
int createLine;
unsigned long createPass;
unsigned checkpoint;
unsigned long allocCount;
MEM_BOOL isDeferFreed;
MEM_BOOL isFreeFillSuppressed;
MEM_BOOL isReadOnly;
MEM_BOOL isNoFree;
MEM_BOOL isNoRealloc;
unsigned long threadID;
unsigned long pid;
} DBGMEM_PTR_INFO;

The isInUse field is non-zero if the allocation is currently in use (allocated), otherwise zero.

The createAPI field identifies the function that created the allocation (see the definition for MEM_API in heapagnt.h for a list of API codes). createFile, createLine, and createPass identify the source file location of the call that created the allocation. These fields will be zero if that source file was not compiled for Debug SmartHeap.

The allocCount field is a unique identifier for the allocation. The allocation count increases by one each time an allocation is made. The checkpoint field indicates the checkpoint value that was current at the time the allocation was created.

isDeferFreed is non-zero if the allocation is currently in the queue of defer-freed allocations, or zero if the allocation is in use or free. isFreeFillSuppressed is non-zero if filling of free memory was suppressed at the time the allocation was freed, in which case its contents were undisturbed when it was freed rather than being filled with the free fill value.

isReadOnly, isNoFree, and isNoRealloc indicate the current protection flags for the allocation, and are set by dbgMemProtectPtr.

The pool field identifies the memory pool that owns the allocation. blockType is MEM_VAR_MOVEABLE_BLOCK for allocations created by MemAlloc, MEM_FS_BLOCK for allocations created by MemAllocFS, MEM_EXTERNAL_BLOCK for allocations larger than one quarter of the pool’s page size, and MEM_VAR_FIXED_BLOCK for all other allocations.

threadID and pid identify the thread and process where the allocation was created. threadID is zero on non multi-threaded platforms. pid is zero on platforms that don’t support SmartHeap shared memory.

Errors Error code Caused by

MEM_BAD_BUFFER name is invalid.

MEM_BAD_POINTER ptr is invalid.

See also dbgMemDeferFreeing, dbgMemProtectPtr, dbgMemSetCheckpoint, dbgMemSuppressFreeFill

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* return an allocation's unique identifier */
unsigned long allocID(void *ptr)
{
DBGMEM_PTR_INFO info;

if (dbgMemPtrInfo(ptr, &info))
return info.allocCount;
}

dbgMemReallocMoves

Determines whether realloc always moves allocations to another place in memory or tries to resize the allocations in place.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL
dbgMemReallocMoves(MEM_BOOL bReallocMoves);

Return value Non-zero if successful, otherwise zero.

Description In most C runtime libraries, realloc resizes an allocation in place, if possible. You can’t know whether an allocation was moved, so you must refer to it using the new address. However, if you mistakenly continue to refer to the original address, the bug may not be immediately apparent — if realloc successfully resized the allocation in place, it also returned the original address.

If you toggle this option on, realloc always moves an allocation and fills the old location with the free fill value. Thereafter, if your program frees or references the allocation at the old address, Debug SmartHeap detects this as an error.

Windows 16-bit The “realloc always moves” setting is global to all applications that link with the Debug SmartHeap Library. Changing it in one task affects reallocations in other currently running tasks and DLLs.

See also dbgMemProtectPtr

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* make appropriate Debug SmartHeap calls to
* prepare for increased overwrite detection
*/
void DetectOverwrites()
{
/* turn on auto heap checking */
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);

/* check on every heap-related call */
dbgMemSetCheckFrequency(1);

/* defer freeing for */
dbgMemDeferFreeing(TRUE);

/* make the defer-freeing queue very long */
dbgMemSetDeferQueueLen(10000);

/* have realloc always move allocations */
dbgMemReallocMoves(TRUE);
}

dbgMemReportLeakage

Reports unfreed memory in a memory pool.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemReportLeakage(MEM_POOL pool,
unsigned chk1, unsigned chk2);

Return value Returns non-zero if pool is valid and checkpoint parameters are non-zero (valid), otherwise zero.

Description dbgMemReportLeakage calls the current error-handling function once for each non-freed block in pool that is marked with a checkpoint between chk1 and chk2. The error code passed to the error handler is MEM_LEAKAGE.

If you have not called dbgMemSetCheckpoint to establish one or more checkpoints, then supply the value 1 both for chk1 and for chk2 (this is the default checkpoint value).

You can write your own error-handling routine to display or record the leakage report (see MemSetErrorHandler). Alternatively, dbgMemSetDefaultErrorOutput lets you control the default error handler. The default error handler normally displays a prompt for each instance of leakage, but having output go to a file is often preferable if there are many leaks.

Comments The closer you can get to the source of leakage, the easier it is to track down. You can use dbgMemSetCheckpoint to mark off a region of code that should have no net change in allocations. You can then call dbgMemReportLeakage and specify that checkpoint to verify that that region of code is, in fact, not leaking.

This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also MemSetErrorHandler, dbgMemSetCheckpoint, dbgMemSetDefaultErrorOutput

Example #define MEM_DEBUG 1
#include <smrtheap.h>

void LeakageReport(void);

/* generate leakage report at program exit */
void main()
{
/* for C, use atexit */
atexit(LeakageReport);

/* ... */
}

/* for C++, use a static class' destructor */
class ShowLeakage {
ShowLeakage::~ShowLeakage()
{ LeakageReport(); }
};
static ShowLeakage leaks;

void LeakageReport()
{
/* have report go to a file */
dbgMemSetDefaultErrorOutput(
DBGMEM_OUTPUT_FILE, "leakage.out");

/* generate leakage report for all allocs */
dbgMemReportLeakage(NULL, 1, 1);
}

dbgMemReportWrongTaskRef (16-bit Windows only)

Determines whether Debug SmartHeap reports as errors references to non-shared memory from the wrong task.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemReportWrongTaskRef(
MEM_BOOL bReportWrongTaskRef);

Return value Non-zero if successful, otherwise zero.

Description Debug SmartHeap normally checks all pointer parameters to verify that they were allocated from the current task, since passing non-shared memory between tasks is usually an error.

If you application intentionally references non-shared memory from more than one task, you can suppress SmartHeap’s reporting of this error by passing zero to dbgMemReportWrongTaskRef.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemProtectPtr

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* suppress reporting of references to
* non-shared memory from the wrong task
*/
void main()
{
dbgMemReportWrongTaskRef(0);

...
}

dbgMemScheduleChecking

Controls the background thread that performs continuous incremental heap checking.

Note dbgMemScheduleChecking is a new API present only in SmartHeap 3.1 and higher.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemScheduleChecking(
MEM_BOOL bEnabled, int priority,
unsigned interval);

Return value Returns non-zero if successful, otherwise zero.

Description dbgMemScheduleChecking creates, destroys, or controls the Debug SmartHeap background heap-checking thread. By default, no background heap checking occurs. Call this function with a non-zero bEnabled parameter to turn background heap-checking on, or with bEnabled as zero to turn background checking off.

The priority parameter controls the priority of the background checking thread. Specify a valid thread-priority value for your operating system. You should generally specify a low, or “idle,” priority for the background-checking thread to avoid slowing your application.

The interval parameter controls how often the background checking thread runs. The thread will sleep for interval milliseconds between each heap check. The background thread locks the pool it is currently checking during each check. Therefore, to ensure that the background thread doesn’t cause your main threads to block waiting for the memory pool, you should generally specify a non-zero value for interval, such as 100.

The checking performed by the background thread is incremental. The background thread checks only one page of memory between each interval, so if you specify a low priority and non-zero interval, the performance impact of the background checking is negligible regardless of your application’s heap size.

Comments This function is available only on platforms that support multi-threading, and only in multi-threaded versions of the SmartHeap library. See the Getting Started and Platform Guide for information on SmartHeap multi-threading support for your platform.

This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also MemPoolCheck, dbgMemSetCheckFrequency

Example #define MEM_DEBUG 1
#include <smrtheap.h>

#define TRUE 1
#define FALSE 0

/* turn on background heap checking, with
* idle priority and an interval of 100
* milliseconds, in Windows NT
*/
void EnableBackgroundChecking()
{
/* turn on background checking */
dbgMemScheduleChecking(TRUE, THREAD_PRIORITY_IDLE,
100);
}

dbgMemSetCheckFrequency

Establishes the default check frequency, which determines how often Debug SmartHeap checks for overwrites when safety level is Debug.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

unsigned dbgMemSetCheckFrequency(unsigned freq);

Return value Previous check frequency if freq is valid (non-zero), otherwise zero.

Description If safety level is Debug, the check frequency determines how often Debug SmartHeap checks for overwrites. The default check frequency is 10: every 10th time your application calls a heap-related function, SmartHeap checks the entire heap for overwrites. This is a very effective way to find overwrites. However, if your application creates a lot of allocations, frequent checks can slow the application to a crawl.

If you want SmartHeap to:

Check for overwrites more often than every 10th function call, specify a value less than 10.

Check for overwrites less often than every 10th function call, specify a value greater than 10.

Note The less frequently you check memory, the faster the application runs: if you only check memory once every 100 calls, checking will be 10 times faster than it will with a check at every 10th call. However, SmartHeap may then not detect overwrites as early.

You can use dbgMemPoolSetCheckFrequency to set the check frequency for individual pools.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemSetSafetyLevel, dbgMemPoolSetCheckFrequency

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* adjust check frequency according to the
stability of various portions of code */
void CodeUnderDevelopment()
{
/* crank up safety */
MEM_SAFETY_LEVEL savedSafety =
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);

/* fn1 was just written -- check heap
on every heap-related call */
unsigned oldFreq = dbgMemSetCheckFrequency(1);
fn1(...);

/* fn2 is very stable -- revert to
previous checking frequency */
dbgMemPoolSetCheckFrequency(oldFreq);
fn2(...);

/* restore safety level */
dbgMemSetSafetyLevel(savedSafety);
}

dbgMemSetCheckpoint

Establishes an allocation context for the current task or process.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

unsigned dbgMemSetCheckpoint(unsigned chkpt);

Return value If chkpt is non-zero (meaning valid), returns previous checkpoint value, otherwise returns zero.

Description Each memory block allocated in the Debug SmartHeap library maintains a record of the current checkpoint at the time the block was allocated. You can therefore use the checkpoint as a way to group related allocations. Checkpoints can give a meaningful context to an allocated block — a block that might otherwise appear to be a meaningless sequence of bytes.

If you don’t call this function, the default checkpoint value is 1.

When SmartHeap reports errors, it identifies the checkpoint of any object involved in the error. Checkpoints can therefore be a useful way to quickly identify the functional or logical group to which the allocation belongs. For example, you might give allocations used for a printing process the value 2 and give allocations used for a searching process the value 3. Note that the same object types could well be allocated for both processes — perhaps even from the same spot in your source code.

Two common uses for checkpoints are for tracking down overwrites or leakage. When an object has been overwritten, knowing how the object is used helps greatly in finding the cause. For leakage detection, dbgMemReportLeakage takes a range of checkpoints so you can ensure that individual functional processes are freeing their allocations.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also MemSetErrorHandler, dbgMemFormatErrorInfo, dbgMemFormatCall, MemDefaultErrorHandler, dbgMemReportLeakage

Example #define MEM_DEBUG 1
#include <smrtheap.h>

#define CP_OPEN 2
#define CP_CALC 3
#define CP_PRINT 4
#define CP_CLOSE 5

/* use checkpoints to group allocations
by functional or logical groups */
void main()
{
dbgMemSetCheckpoint(CP_OPEN);
Open();
dbgMemSetCheckpoint(CP_CALC);
Calc();
dbgMemSetCheckpoint(CP_PRINT);
Print();

/* Calc and Print should have freed
all of their allocations */
dbgMemReportLeakage(NULL, CP_CALC,CP_PRINT);

dbgMemSetCheckpoint(CP_CLOSE);
Close();

/* Close should free Open's allocs */
dbgMemReportLeakage(NULL, CP_OPEN,CP_CLOSE);
}

dbgMemSetDefaultErrorOutput

Controls I/O behavior of the default error handler.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemSetDefaultErrorOutput(
unsigned flags, const char *file);

Return value Returns zero (failure) if an output file is specified but can’t be opened, otherwise non-zero (success).

Description dbgMemSetDefaultErrorOutput defines the behavior of the Debug SmartHeap default error handler. The default error handler can perform any combination of interactive prompt, logging to a file, audible beep, and logging to a debugging console.

To construct the flags parameter, bitwise OR one or more of the following values:

DBGMEM_OUTPUT_PROMPT

Interactive prompt with Abort, Ignore, and possibly Retry.

DBGMEM_OUTPUT_CONSOLE

Log to debug console.

DBGMEM_OUTPUT_BEEP

Audible alarm.

DBGMEM_OUTPUT_FILE

Open new file for error logging.

DBGMEM_OUTPUT_FILE_APPEND

Append to existing error log file.

The default error output setting is DBGMEM_OUTPUT_PROMPT. This is also the only choice for the default error handler in the Runtime SmartHeap library.

You can call dbgMemSetDefaultErrorOutput at any time to dynamically change error reporting behavior. For example, it is useful to set error output to file just before calling dbgMemReportLeakage.

Important! If output to a file doesn’t seem to be working, test the return value of this function — the function returns zero only if output to file is specified and the file can’t be opened.

Comments You can customize error handling further with MemSetErrorHandler, dbgMemFormatCall, and dbgMemFormatErrorInfo.

This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also MemDefaultErrorHandler, dbgMemFormatErrorInfo, dbgMemFormatCall, MemSetErrorHandler, dbgMemSetEntryHandler, dbgMemSetExitHandler, dbgMemReportLeakage

Example #define MEM_DEBUG 1
#include <smrtheap.h>

void UbiquitousErrorIO()
{
/* send error I/O everywhere at once */
dbgMemSetDefaultErrorOutput(
DBGMEM_OUTPUT_PROMPT |
DBGMEM_OUTPUT_CONSOLE |
DBGMEM_OUTPUT_BEEP |
DBGMEM_OUTPUT_FILE,
"myerrors.log");
}

dbgMemSetDeferQueueLen

Sets the default number of defer-freed allocations that Debug SmartHeap retains in the queue.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

unsigned long dbgMemSetDeferQueueLen(
unsigned long queueLength);

Return value The previous queue length, if queueLength is valid (non-zero), otherwise zero.

Description When deferred freeing is on, freed allocations aren’t actually freed, they’re placed in a queue. When the number of defer-freed allocations reaches queueLength, the oldest allocation in the queue is returned to the free pool for reuse. If you don’t call this function, the default queue length is 1000. The maximum is ULONG_MAX - 1.

dbgMemSetDeferQueueLen changes the queue length for all memory pools. If you want to change the queue length for an individual pool, call dbgMemPoolSetDeferQueueLen.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemDeferFreeing, dbgMemFreeDeferred, dbgMemPoolSetDeferQueueLen, dbgMemSetDeferSizeThreshold

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* make appropriate Debug SmartHeap calls to
* prepare for increased overwrite detection
*/
void DetectOverwrites()
{
/* turn on auto heap checking */
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);

/* check on every heap-related call */
dbgMemSetCheckFrequency(1);

/* defer freeing for */
dbgMemDeferFreeing(TRUE);

/* make the defer-freeing queue very long */
dbgMemSetDeferQueueLen(10000);

/* have realloc always move allocations */
dbgMemReallocMoves(TRUE);
}

dbgMemSetDeferSizeThreshold

Sets the maximum size of an allocation that is added to the queue of defer-freed allocations.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

unsigned long dbgMemSetDeferSizeThreshold(
unsigned long threshold);

Return value Returns previous deferred-freeing size threshold.

Description Allocations larger than the threshold are freed immediately to prevent consuming too much memory. The default threshold is 4,096 bytes.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemDeferFreeing, dbgMemFreeDeferred, dbgMemSetDeferQueueLen

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* make appropriate Debug SmartHeap calls to
* prepare for increased overwrite detection
*/
void DetectOverwrites()
{
/* turn on auto heap checking */
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);

/* check on every heap-related call */
dbgMemSetCheckFrequency(1);

/* defer freeing for */
dbgMemDeferFreeing(TRUE);

/* make the defer-freeing queue very long */
dbgMemSetDeferQueueLen(10000);

/* defer freeing of large allocations */
dbgMemSetDeferSizeThreshold(60000);

/* have realloc always move allocations */
dbgMemReallocMoves(TRUE);
}

dbgMemSetEntryHandler, dbgMemSetExitHandler

Establishes entry and exit trace hooks.

Syntax #include <smrtheap.h>
MEM_TRACE_FN
dbgMemSetEntryHandler(MEM_TRACE_FN entryFn);
MEM_TRACE_FN
dbgMemSetExitHandler(MEM_TRACE_FN exitFn);

Return value If successful, returns the trace routine that was in effect for the current task prior to this call, otherwise NULL.

Description dbgMemSetEntryHandler and dbgMemSetExitHandler provide hooks that allow your trace functions to be called on entry to and/or exit from every SmartHeap API in the debugging SmartHeap library.

entryFn and exitFn have the following prototype:

void MEM_CALLBACK TraceFn(MEM_ERROR_INFO *,
unsigned long);

Replace TraceFn, above, with your function name.

Windows 16-bit In 16-bit Windows, TraceFn must follow the rules for callback functions in Windows: exported, and DS set up on entry (for example, with MakeProcInstance and/or export).

The MEM_ERROR_INFO parameter of TraceFn points to a structure that identifies the API and parameters. For details on this structure, see MemSetErrorHandler. Note that the errorCode field of MEM_ERROR_INFO isn’t relevant for the trace functions, since the functions do not report errors.

You can use dbgMemFormatCall to print the function name and parameters, or you can programmatically analyze the information from your error handler.

The unsigned long parameter of TraceFn is a boolean that indicates whether the parameters are valid for entryFn and the function’s return value for exitFn. Cast this unsigned long value to the appropriate return type, depending on the errorAPI field of MEM_ERROR_INFO.

Caution! Your trace function must not call any SmartHeap functions other than dbgMemFormatCall, unless you implement a mechanism to detect and terminate the infinite recursion that would result. You must also be careful to avoid compiler runtime library functions that might be calling malloc, including the printf family and most stream I/O functions.

Comments These functions are available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the functions are defined as macros that expand to zero. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

Windows 16-bit For 16-bit Windows, dbgMemSetEntryHandler establishes an error handler for the current Windows module instance (for the current task, if called from an EXE, or for the calling DLL, if called from a DLL).

See also dbgMemFormatCall, MemSetErrorHandler

Example #include <smrtheap.h>

/* trace all SmartHeap calls to dbg monitor */
void MEM_CALLBACK MyTraceFn(MEM_ERROR_INFO *info,
unsigned long bValidParms)
{
char buf[128];
dbgMemFormatCall(info, buf, 127);
OutputDebugString(buf);
}

int main()
{
/* establish trace handler */
dbgMemSetEntryHandler(MyTraceFn);

/* ... */
}

dbgMemSetGuardSize, dbgMemGuardSize

dbgMemSetGuardFill, dbgMemGuardFill
dbgMemSetFreeFill, dbgMemFreeFill
dbgMemSetInUseFill, dbgMemInUseFill

Customizes overwrite guard sizes and fill values.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemSetGuardSize(unsigned size);
MEM_BOOL dbgMemSetGuardFill(unsigned char gf);

MEM_BOOL dbgMemSetFreeFill(unsigned char ff);
MEM_BOOL dbgMemSetInUseFill(unsigned char uf);
const unsigned dbgMemGuardSize;
const unsigned char dbgMemGuardFill;
const unsigned char dbgMemFreeFill;
const unsigned char dbgMemInUseFill;

Return value Returns non-zero (success) if there are no memory pools in the current task or process, otherwise zero (failure).

Description dbgMemSetGuardSize sets the size in bytes of leading and trailing memory block guards to size. size may be rounded up for alignment — to the nearest 4 bytes on most platforms. Default guard size is 4 bytes.

dbgMemSetGuardFill

Sets the character used to fill memory block guards to the value of gf — default is 0xFC.

dbgMemSetFreeFill

Sets the character used to fill free memory blocks to the value of ff — default is 0xDD.

dbgMemSetInUseFill

Sets the character used to fill just-allocated memory blocks to the value of uf — default is 0xEB.

These functions must be called before the first memory pool is created. Since the compiler startup code might call malloc (which implicitly creates a pool) before your application gets control, SmartHeap provides global variables as an alternative to the functions. If you define one or more of the dbgMemXXX global variables, then the first call to malloc will call the corresponding dbgMemSetXXX functions immediately before creating the default memory pool.

Note These functions are not supported in Win32 unless HeapAgent is installed.

Comments If you’re trying to isolate a memory overwrite, or if you suspect an overwrite is occurring, you can increase the guard size to increase the probability that the overwrite will occur on a guard. SmartHeap will then detect the overwrite and pinpoint the block most likely to be responsible.

Set the safety level to MEM_SAFETY_DEBUG to enable automatic overwrite checking (see example below).

These functions are available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemDeferFreeing, dbgMemProtectPtr, MemPoolCheck, dbgMemPoolSetCheckFrequency

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* set guard size to 20 bytes, fill with 0xAA */
const unsigned dbgMemGuardSize = 20;
const unsigned char dbgMemFreeFill = 0xAA;

void main()
{
/* turn on auto heap checking */
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);
}

dbgMemSetSafetyLevel

Changes the safety level for the current task or process.

Syntax #include <smrtheap.h>

MEM_SAFETY_LEVEL dbgMemSetSafetyLevel(
MEM_SAFETY_LEVEL safetyLevel);

Return value Returns the safety level that was in effect for the current task prior to this call or -1 if safetyLevel is invalid.

Description dbgMemSetSafetyLevel lets you control the level of checking performed by the SmartHeap functions. You may pass one of the following values for the safetyLevel parameter:

MEM_SAFETY_SOME

Parameters are fully validated, leading and trailing guards are set and tested, and free blocks are filled. All constant-overhead checks are performed, but no checks that are not O(c) are done — so free-lists are not scanned, for instance. Use this setting for minimum runtime impact; it catches most common runtime errors.

MEM_SAFETY_FULL

This is the default setting for the Debug SmartHeap library. In addition to the checks above, this setting fills all newly-allocated blocks with the in-use pattern. Certain O(n) checks are also performed at this level, such as scanning free-lists to detect double-freeing. This level is slower than MEM_SAFETY_SOME but is generally only a factor of 2 or 3 slower than the runtime library.

MEM_SAFETY_DEBUG

Like MEM_SAFETY_FULL, but the entire memory pool associated with a call is validated on each entry-point to SmartHeap. That makes this level O(n2). This setting can be very slow, but it is very effective at pin-pointing memory overwrites.

Comments To mitigate the speed degradation of MEM_SAFETY_DEBUG, use dbgMemPoolSetCheckFrequency. For example, if you only do a full heap check at every 100 calls, overall performance will be 100 times faster.

Windows 16-bit As with other debugging settings, the safety level in the 16-bit Windows version is set for the current Windows module instance (for the current task, if called from an EXE, or for the calling DLL, if called from a DLL).

This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to a success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemPoolSetCheckFrequency, MemPoolCheck

Example #include <smrtheap.h>

void main()
{
MEM_POOL MyPool = MemPoolInit(0);

/* set safety level to debug, but use
a check frequency so isn't too slow */
dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG);
dbgMemPoolSetCheckFrequency(MyPool, 100);

/* . . . */
}

dbgMemSettingsInfo

Returns the Debug SmartHeap debugging settings associated with the current task or process.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemSettingsInfo(
DBGMEM_SETTINGS_INFO *settingsInfo);

Return value Returns non-zero if the settingsInfo is a valid buffer, otherwise zero.

Description The DBGMEM_SETTINGS_INFO structure is defined as follows:

typedef struct {
MEM_SAFETY_LEVEL safetyLevel;
unsigned checkFrequency;
unsigned long allocCount;
unsigned checkpoint;
MEM_BOOL isDeferFreeing;
unsigned long deferQueueLength;
unsigned long deferSizeThreshold;
MEM_BOOL isFreeFillSuppressed;
MEM_BOOL isReallocAlwaysMoves;
MEM_BOOL isWrongTaskRefReported;
unsigned outputFlags;
const char *outputFile;
unsigned guardSize;
unsigned char guardFill;
unsigned char freeFill;
unsigned char inUseFill;
} DBGMEM_SETTINGS_INFO;

The allocCount field contains the allocation sequence number that will be assigned to the next allocation created.

The table on the following page lists the fields in the DBGMEM_SETTINGS_INFO structure and the API you can use to set each value.

Field API

safetyLevel dbgMemSetSafetyLevel

checkFrequency dbgMemSetCheckFrequency

checkPoint dbgMemSetCheckpoint

isDeferFreeing dbgMemDeferFreeing

deferQueueLength dbgMemSetDeferQueueLen

deferSizeThreshold dbgMemDeferSizeThreshold

isFreeFillSuppressed dbgMemSuppressFreeFill

isReallocAlwaysMoves dbgMemReallocMoves

IsWrongTaskRefReported dbgMemReportWrongTaskRef

outputFlags, outputFile dbgMemSetDefaultErrorOutput

guardSize dbgMemSetGuardSize

guardFill dbgMemSetGuardFill

freeFill dbgMemSetFreeFill

inUseFill dbgMemSetInUseFill

Comments This function is available only in the Debug SmartHeap library. If you don’t define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

Errors Error code Caused by

MEM_BAD_BUFFER settingsInfo is invalid.

See also dbgMemDeferFreeing, dbgMemReallocMoves, dbgMemReportWrongTaskRef, dbgMemSetCheckpoint, dbgMemSetDeferQueueLen, dbgMemSetDeferSizeThreshold, dbgMemSetFreeFill, dbgMemSetGuardSize, dbgMemSetGuardFill, dbgMemSetInUseFill, dbgMemSetSafetyLevel, dbgMemSuppressFreeFill

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* retrieve current checkpoint value */
unsigned getCheckpoint()
{
DBGMEM_SETTINGS_INFO info;

dbgMemSettingsInfo(&info);
return info.checkpoint;
}

dbgMemSuppressFreeFill

Determines whether free and deferred-free allocations are filled with the free fill value.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_BOOL dbgMemSuppressFreeFill(
MEM_BOOL bSuppressFreeFill);

Return value Returns non-zero if successful, otherwise zero.

Description Generally, you should let Debug SmartHeap fill freed allocations, which allows SmartHeap to detect references to free memory. However, some libraries and applications read pointers from memory that has already been freed. If SmartHeap fills freed memory with the free fill value, your application will cause a memory protection violation when dereferencing these pointers. The error is thereby detected immediately, as intended. However, if you can’t fix the error (for example, because it occurs in a third-party library that you don’t have source code to), you’ll probably want to suppress free filling so your application can continue running.

Windows 16-bit Suppression of free filling is global to all applications that link with the Debug SmartHeap Library. If you change the value in one task, this affects free filling in other currently running tasks and DLLs.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemSetFreeFill

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* suppress filling of free memory
* while executing third-party library
* code with known references to free memory
*/
void main()
{
...

dbgMemSuppressFreeFill(1);
erroneousThirdPartyRoutine();
dbgMemSuppressFreeFill(0);

...
}

dbgMemTotalCount

Returns the allocations count for the heap.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

unsigned long dbgMemTotalCount(void);

Return value Total number of allocations in the heap if successful, otherwise MEM_ERROR_RET.

Description dbgMemTotalCount walks the heap and returns the total number of allocations currently in use.

Note Monitoring the allocation count is one way to check for the existence of leakage in your application. If the allocation count steadily increases as your application runs even though the application doesn’t increase the amount of data stored, this is a sign that leakage may exist.

The value returned is the total number of allocations currently in use in all SmartHeap memory pools. To determine the allocation count of a specific memory pool, use the SmartHeap function MemPoolCount.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemReportLeakage, dbgMemTotalSize

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* monitor the allocation count before and after
* an operation that should be freeing everything
* that it allocates:
* an increasing allocation counts signals leakage
*/
main()
{
unsigned long count1, count2;
...

/* record allocation count before operation */
count1 = dbgMemTotalCount();

/* perform application-specific operation */
reportProcess();

/* record allocation count after operation */
count2 = dbgMemTotalCount();

/* check for a net increase in allocations */
if (count2 > count1)
printf("reportProcess() has a memory leak!");

...
}

dbgMemTotalSize

Returns the total amount of memory consumed by the heap.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

unsigned long dbgMemTotalSize(void);

Return value The total amount of memory consumed by the heap if successful, otherwise MEM_ERROR_RET.

Description dbgMemTotalSize walks the heap and returns the total number of bytes of operating system memory that the heap currently uses.

The value returned is the total size of all SmartHeap memory pools. To determine the size of a specific memory pool, use the SmartHeap function MemPoolSize.

Note Monitoring the heap size is one way to check for the existence of leakage in your application. If the heap size steadily increases as your application runs, while the application does not increase the amount of data stored, this is a sign that leakage may exist.

You can also monitor the heap size and send an alert if your application uses more than a predetermined amount of memory; this can prevent an out-of-memory condition from arising.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as a macro that expands to success result. This lets you have SmartHeap debugging functions in your source code without #ifdef statements.

See also dbgMemReportLeakage, dbgMemTotalCount

Example #define MEM_DEBUG 1
#include <smrtheap.h>

/* periodically check the total heap size;
* display a message if the heap size is
* greater than 1MB
*/
void checkHeapSize()
{
/* total heap size greater than 1MB? */
if (dbgMemTotalSize() > 0x100000)
printf("Using excessive heap memory!");
}

dbgMemWalkHeap

Traverses heap allocations in the default memory pool.

Syntax #define MEM_DEBUG 1
#include <smrtheap.h>

MEM_POOL_STATUS dbgMemWalkHeap(
MEM_POOL_ENTRY *heapEntry);

Return value Returns:

Description Each call to dbgMemWalkHeap traverses one block in the default memory pool, whether free or in use, reports any errors encountered, and returns information about the entry. The MEM_POOL_ENTRY structure is defined as follows:

typedef struct {
void *entry;
heap entry pointer
MEM_POOL pool;
pool containing the entry
MEM_BLOCK_TYPE type;
block type of entry
MEM_BOOL isInUse;
zero if entry free; else non-zero
unsigned long size;
entry size in bytes
MEM_HANDLE handle;
handle, if handle-based block
unsigned lockCount;
lock count, if handle-based
} MEM_POOL_ENTRY;

typedef enum {
MEM_FS_BLOCK,
MEM_VAR_MOVEABLE_BLOCK,
MEM_VAR_FIXED_BLOCK,
MEM_EXTERNAL_BLOCK
} MEM_BLOCK_TYPE;

If the return value is MEM_POOL_OK or MEM_POOL_CORRUPT, heapEntry contains valid data, and you can call dbgMemWalkHeap again to continue walking the heap to retrieve additional heap data. If the return value is MEM_POOL_END or MEM_POOL_CORRUPT_FATAL, heapEntry does not contain valid data and you either have reached the end of the heap or have encountered heap corruption that prevents SmartHeap from walking the remainder of the heap.

Important! The first time you call dbgMemWalkHeap, you must set the entry field of poolEntry to NULL; the function then obtains information about the first allocation. Each subsequent call to dbgMemWalkHeap obtains data about subsequent allocations.

Caution! If your application contains more than one thread, you must call MemPoolLock(MemDefaultPool)before calls to dbgMemWalkHeap and MemPoolUnlock(MemDefaultPool) after calls to dbgMemWalkHeap. Otherwise, the state stored in heapEntry between calls to dbgMemWalkHeap would be invalidated.

Comments This function is available only in the Debug SmartHeap library. If you do not define the macro symbol MEM_DEBUG before including smrtheap.h, the function is defined as an empty macro.

Errors Error code Caused by

MEM_BAD_BLOCK A corrupt (overwritten) block was detected.

MEM_BAD_FREE_BLOCK A corrupt free block was detected.

See also dbgMemPtrInfo, MemPoolWalk

Example #define MEM_DEBUG 1
#include <string.h>
#include <smrtheap.h>

/* Search all allocations in the heap for
the specified character string. */
const char *SearchHeap(const char *str) {
MEM_POOL_ENTRY entry;
unsigned len = strlen(str) + 1;

entry.entry = NULL;

while (dbgMemWalkHeap(&entry) == MEM_POOL_OK)
if (entry.isInUse && len <= entry.size
&& memcmp(entry.entry, str, len) == 0)
return (const char *)entry.entry;

return NULL;
}

delete

C++ memory deallocation operator.

Syntax delete mem;

Return value None

Description The delete operator deallocates a memory block previously allocated by C++ global operator new.

smrtheap.hpp isn’t required for operator delete.

Important! The SmartHeap library defines the ::operator delete function, overriding the definition present in your C++ runtime library. You must specify the SmartHeap library to your linker before you specify your C++ runtime library to ensure that you get SmartHeap’s function rather than the compiler’s function. If you do not want to override your compiler’s global operator delete for some reason, you must remove the shnew object module from the SmartHeap library (see §2.3.4 for instructions).

Comments In 16-bit x86 versions of SmartHeap, ::operator delete is a far function accepting a far pointer regardless of memory model. Therefore, it requires the large memory model. If you use a memory model other than large, you can use the MemFreePtr function to free blocks allocated with operator new. You can also overload operator delete as a class member function in all memory models.

Errors Error code Caused by

MEM_BAD_POINTER mem is an invalid pointer.

MEM_DOUBLE_FREE mem was previously freed.

MEM_NOFREE mem was marked as “no free” by dbgMemProtectPtr.

MEM_WRONG_TASK mem was allocated in a different task.

See also free, MemFreePtr, MemPoolFree, MemFreeFS, new

Example #include <smrtheap.hpp>

// example list Link class definition
class Link {
public:
Link(int init=0) : value(init), next(0) {}
~Link() {}

// overload operators new and delete to
// allocate Link's from fixed-size pool
void far *operator new(size_t)
{ return MemAllocFS(pool); }
void operator delete(void *mem)
{ MemFreeFS(mem); }

int value;
Link *next;
static MEM_POOL pool;
};

// initialize static member 'pool' at startup
// (before WinMain) to a fixed-size pool with
// block size equal to the size of Link object
MEM_POOL Link::pool =
MemPoolInitFS(sizeof(Link), 10, 0);

int main()
{
// allocate a list Link with value 3
Link *head = new Link(3);
delete head; // free the link
MemPoolFree(Link::pool); // and free pool

// non-shared pool for variable-size objects
MEM_POOL var_pool = MemPoolInit(0);
// allocate a 20 char string from this pool
char *str = new(var_pool) char[20];
delete str; // free the string
MemPoolFree(var_pool); // and free pool

return 1;
}

free

ANSI C standard memory deallocator.

Syntax #include <shmalloc.h> macro or debug version, or
#include <stdlib.h> ANSI function version

void free(void *block);

Return value None

Description The free function deallocates a block previously allocated with calloc, malloc, realloc, ::operator new, MemAllocPtr, MemReAllocPtr, or MemAllocFS. If block is NULL, free does nothing.

Important! The SmartHeap library defines the free function, overriding the definition present in your C runtime library. You must specify the SmartHeap library to the linker before you specify your C runtime library to ensure that you get SmartHeap’s function rather than the compiler’s function. If you do not want to override your compiler’s free function for some reason, you must remove the shmalloc object module from the SmartHeap library (see §2.3.3 for instructions). In this case, you can still have free calls go to SmartHeap by including shmalloc.h in each of your source modules — this header file defines free as a macro rather than as a function.

Comments In 16-bit x86 versions of SmartHeap, free is a far function accepting a far pointer regardless of memory model. Therefore, you must either use the large memory model or use the macro version of free as described above. SmartHeap also overrides either _ffree or farfree as synonyms for free, for compilers that define one of these functions. As another alternative, you can use the MemFreePtr function in all memory models.

Errors Error code Caused by

MEM_BAD_POINTER block is an invalid pointer.

MEM_DOUBLE_FREE block was previously freed.

MEM_NOFREE block was marked as “no free” by dbgMemProtectPtr.

MEM_WRONG_TASK block was allocated in a different task.

See also calloc, delete, malloc, MemFree, MemFreeFS, MemFreePtr, MemPoolFree

Example #include <shmalloc.h>
#define TRUE 1
#define FALSE 1

int DisplayError(char *msg, int num)
{
/* allocate buffer in which to format msg */
char *buf =
(char *)malloc(strlen(msg) + 20);

/* return if allocation failed */
if (buf == NULL)
return FALSE;

/* format and display the message */
sprintf(buf, "Error #%d: %s.", num, msg);
MessageBox(GetFocus(), buf, NULL, MB_OK);

/* free the buffer */
free(buf);

return TRUE;
}

malloc

ANSI C standard general purpose memory allocator.

Syntax #include <shmalloc.h> macro or debug version, or
#include <stdlib.h> ANSI function version

void *malloc(size_t size);

Return value Returns a pointer to the allocated space. The return value is NULL if there is insufficient memory.

Description The malloc function allocates a block at least size bytes in size. Use MemSizePtr to determine the block’s actual size. The memory is uninitialized.

malloc allocates from the default memory pool implicitly defined by SmartHeap for the task or process from which you call malloc. If you wish to call a memory pool function for this default pool (MemPoolSize, MemPoolCount, etc.), supply MemDefaultPool for the pool parameter.

If size is zero, malloc returns a pointer to zero bytes of memory.

The maximum size of a single block that can be allocated with malloc is UINT_MAX minus approximately 24 bytes. Use MemAllocPtr for larger blocks on 16-bit platforms.

Important! The SmartHeap Library defines the malloc function, overriding the definition present in your C runtime library. You must specify the SmartHeap Library to your linker before you specify your C runtime library to ensure that you get SmartHeap’s function rather than the compiler’s function. If you do not want to override your compiler’s malloc function for some reason, you must remove the shmalloc object module from the SmartHeap library (see §2.3.3 for instructions). In this case, you can still have malloc calls go to SmartHeap by including shmalloc.h in each of your source modules — this header file defines malloc as a macro rather than a function.

Comments In 16-bit x86 versions of SmartHeap, malloc is a far function returning a far pointer regardless of memory model. Therefore, you must either use the large memory model or use the macro version of malloc as described above. SmartHeap also overrides either _fmalloc or farmalloc for compilers that define one these functions.

Errors Error code Caused by

MEM_ALLOC_ZERO size is zero.

MEM_BLOCK_TOO_BIG size exceeds UINT_MAX - 24.

MEM_EXCEEDED_CEILING Total allocations in default memory pool exceed the size specified by MemPoolSetCeiling.

MEM_OUT_OF_MEMORY There is insufficient operating system memory to satisfy allocation request.

See also calloc, free, MemAlloc, MemAllocFS, MemAllocPtr, MemSizePtr, new, realloc

Example #include <shmalloc.h>

#define TRUE 1
#define FALSE 0
int DisplayError(char *msg, int num)
{
/* allocate buffer in which to format msg */
char *buf = (char *)malloc(strlen(msg)+20);
if (buf == NULL)
return FALSE; /* allocation failed */

/* format and display the message */
sprintf(buf, "Error #%d: %s.", num, msg);
MessageBox(GetFocus(), buf, NULL, MB_OK);

free(buf); /* free the buffer */
return TRUE;
}

MemAlloc

Handle-based variable-size block allocator for moveable memory.

Syntax #include <smrtheap.h>

MEM_HANDLE MemAlloc(MEM_POOL pool, unsigned flags,
unsigned long size);

Return value Returns a handle of type MEM_HANDLE to the allocated space. The return value is NULL if there is insufficient memory, if pool is invalid, or if size is zero.

Description The MemAlloc function allocates a block size bytes in size. The memory block can be either fixed or moveable, as specified by the flags parameter. The memory is uninitialized unless you supply MEM_ZEROINIT with flags.

The size of the block allocated will be at least size, possibly larger. You can determine the exact size of a block with MemSize.

Use MemPoolInit to create pool.

You can reference the memory corresponding to a MEM_HANDLE with MEM_REFERENCE, MemLock, or MemFix.

To construct the flags parameter, bitwise OR one or more of the following values:

MEM_FIXED

Allocates fixed (non-moveable) memory. Can’t use with MEM_MOVEABLE.

MEM_MOVEABLE

Allocates moveable memory. Can’t be used with MEM_FIXED.

MEM_NOCOMPACT

Avoids compacting memory to satisfy the allocation request. Use this flag if a particular call to MemAlloc needs to be as fast as possible.

MEM_NOEXTERNAL

Always sub-allocates. Fails if pool needs to grow and there is insufficient memory to add an entire new page.

MEM_NOGROW

Avoids expanding the heap to satisfy the allocation request. The allocation fails if it does not fit in existing free space within the heap.

MEM_RESIZEABLE

Reserves space just above the block, so a subsequent MemReAlloc is more likely to succeed.

MEM_ZEROINIT

Initializes memory contents to zero.

Each SmartHeap memory pool maintains two heaps for handle-based allocations: a moveable heap and a fixed heap. Blocks allocated with MEM_MOVEABLE are allocated from the moveable heap and have an initial lock count of zero. Blocks allocated with MEM_FIXED (the default) are put on the fixed heap and have an initial lock count of one. The purpose of the dual heaps is to keep the moveable heap completely free of fragmentation.

MemUnfix causes a block initially allocated with MEM_FIXED to become moveable; likewise, MemFix moves a block allocated with MEM_MOVEABLE to the fixed heap.

Comments The MEM_HANDLE type is defined as a pointer to a structure to facilitate compile-time type checking. The value returned is actually a pointer to a pointer to the allocated space. You should use the MEM_REFERENCE macro to efficiently de-reference the handle rather than directly using the C * dereference operator. This is because the MEM_REFERENCE macro expands to an error-checking function in the debug version of SmartHeap.

If you do not need moveable memory, use MemAllocPtr rather than MemAlloc. MemAllocPtr provides faster allocations and eliminates the need for you to deal with memory handles. If you’re allocating many blocks of the same size (for a linked list, for example), use MemAllocFS. This is much faster and eliminates the problems of overhead and fragmentation present in variable-size allocations.

In 16-bit x86 versions of SmartHeap, if you supply a value for size greater than approximately 65510, you will need to address the returned memory block with a huge pointer. Note that the offset of such huge blocks isn’t zero. Therefore, if you allocate a huge array of structures, an individual structure may straddle segment boundaries even if the structure size is a power of two. Huge arrays of structures are therefore best allocated directly from the operating system (so offset is zero).

Errors Error code Caused by

MEM_ALLOC_ZERO size is zero.

MEM_BAD_FLAGS Invalid flags parameter.

MEM_BAD_MEM_POOL pool is invalid.

MEM_EXCEEDED_CEILING Total allocations in pool exceed size specified by MemPoolSetCeiling.

MEM_OUT_OF_MEMORY There is insufficient memory to satisfy the allocation request.

MEM_WRONG_TASK pool belongs to a different task.

See also MemAllocPtr, MemFix, MemFree, MemLock, MemIsMoveable, MemPoolInit, MemReAlloc, MEM_REFERENCE, MemSize, NewHandle (Chap. 14)

Example #include <smrtheap.h>

/* StringPool is a global variable assumed here to have
* been previously initialized with MemPoolInit.
*/
extern MEM_POOL StringPool;
MEM_HANDLE hStringTable = NULL;

/* initialize a string table */
int InitStringTable(unsigned size)
{
/* initialize table to size entries */
hStringTable = MemAlloc(StringPool,
MEM_ZEROINIT | MEM_MOVEABLE,
sizeof(char *) * size);
return hStringTable != NULL;
}

/* lock moveable block and update contents */
int SetString(int index, char *value)
{
/* lock table in memory */
char * *pStringTable =
(char * *)MemLock(hStringTable);

if (!pStringTable)
return FALSE;
/* update string table entry */
pStringTable[index] = value;

/* unlock the table */

MemUnlock(hStringTable);

return TRUE;

}

MemAllocAligned

Returns memory aligned on any boundary desired.

Note MemAllocAligned is a new API present only in SmartHeap 5 and higher.

Syntax #include <smrtheap.h>

void * MemAllocAligned(MEM_POOL pool, unsigned long blockSize, unsigned long Size, unsigned Flags);

Return value Returns a null pointer upon failue.

Description MemAllocAligned returns a block of memory of Size bytes aligned to blocksize. The blocksize must be given as a power of two. See the entry for MemAllocPtr, elsewhere in this doc, for a list of valid Flags values.

Important note on alignment

The ANSI standard specifies that malloc and new return memory suitably aligned for any object, but SmartHeap potentially returns non-aligned memory in order to conserve space. Specifically, SmartHeap’s small block allocator (SBA) aligns on a word multiple. The first SBA block in a page is aligned on a double boundary, but subsequent blocks are aligned on a word multiple. So on a 32-bit architecture, a 4-byte SBA request will return 4-byte aligned, but an 8-byte request will return 8-byte aligned memory. Typically, compilers pad structures that contain doubles to a double multiple, so doubles will generally be suitably aligned even with SBA. However, this isn’t guaranteed.

To guarantee that calls to malloc and new will have sizeof(double) alignment, you must disable the SBA. SmartHeap’s medium and large blocks always align on double boundaries.

To disable the SBA, use the following call:

#include <smrtheap.h>MemPoolSetSmallBlockAllocator(MemDefaultPool, MEM_POOL_SMALL_BLOCK_NONE);

MemAllocFS

Allocates fixed-size blocks for C structures, C++ objects, etc.

Syntax #include <smrtheap.h>

void *MemAllocFS(MEM_POOL pool);

Return value Returns a pointer to the allocated space. The return value is NULL if there is insufficient memory or if pool is invalid.

Description The MemAllocFS function allocates a block whose size is determined by the block size of the memory pool pool. The memory is uninitialized. Use MemPoolInitFS or MemPoolInit to create pool.

Comments MemAllocFS is recommended for any situation where there are many small objects of equal size. Examples include linked lists, trees, and other dynamic data structures. This allocator is extremely fast, incurs no per-allocation overhead, and is fragmentation free (since all blocks in the pool are the same size).

Errors Error code Caused by

MEM_ALLOC_ZERO pool’s fixed-size block size is zero.

MEM_BAD_MEM_POOL pool is invalid.

MEM_EXCEEDED_CEILING Total allocations in pool exceed size specified by MemPoolSetCeiling.

MEM_OUT_OF_MEMORY There is insufficient operating system memory to satisfy the allocation request.

MEM_WRONG_TASK pool belongs to a different task.

See also malloc, MemAlloc, MemAllocPtr, MemFreeFS, MemPoolInitFS, new

Example #include <smrtheap.h>

/* example list link structure */
typedef struct Link {
int value;
struct Link *next;
} *PLINK;

/* Initialize fixed-size pool for links. */
MEM_POOL CreateList(int InitialLinkCount)
{
return MemPoolInitFS(sizeof(struct Link),
InitialLinkCount, 0);
}

/* add a new link to list */
PLINK InsertLink(MEM_POOL LinkPool,
PLINK prev, int val)
{
/* allocate a new Link */
PLINK link = (PLINK)MemAllocFS(LinkPool);
if (link == NULL)
return NULL; /* allocation failed */

/* initialize the new link */
link->value = val;
if (prev) {
link->next = prev->next;
prev->next = link;
}
else
link->next = NULL;
return link;
}

/* free entire list */
int FreeList(MEM_POOL LinkPool)
{
/* Freeing pool frees all memory in pool:
much faster and less error prone than
freeing each element individually! */
return MemPoolFree(LinkPool);
}

MemAllocPtr

Allocates a variable-size block and returns a memory pointer.

Syntax #include <smrtheap.h>
void *MemAllocPtr(MEM_POOL pool,
unsigned
 long size, unsigned flags);

Return value Returns a pointer to the allocated space. The return value is NULL if there is insufficient memory, if size is zero, or if pool isn’t a valid memory pool.

Description The MemAllocPtr function allocates a size byte block. The memory is uninitialized unless flags specifies MEM_ZEROINIT. Use MemPoolInit to create pool.

To construct the flags parameter, bitwise OR one or more of the following values:

MEM_NOEXTERNAL

Always sub-allocates. Fails if there isn’t enough memory to add an entire new page.

MEM_NOGROW

Does not expand pool — allocation must fit within pool’s existing free space.

MEM_RESIZEABLE

Reserves space above the block, so a subsequent realloc is likely to succeed.

MEM_ZEROINIT

Initializes memory contents to zero.

The size of the block allocated will be at least size. You can determine the exact size of a block with MemSizePtr.

MemAllocPtr’s advantage over malloc is that you can specify a memory pool. See §2.4 for details on memory pools.

Comments In 16-bit x86 versions of SmartHeap, if you supply a value for size greater than approximately 65510, you will need to address the returned memory block with a huge pointer. The offset of these blocks is not zero. Therefore, if you allocate a huge array of structures, an individual structure may straddle segment boundaries even if the structure size is a power of two. As a result, huge arrays of structures are best allocated directly from the operating system (so offset is zero).

Errors Error code Caused by

MEM_ALLOC_ZERO size is zero.

MEM_BAD_FLAGS Invalid flags parameter.

MEM_BAD_MEM_POOL pool is invalid.

MEM_EXCEEDED_CEILING Total allocations in pool exceed size specified by MemPoolSetCeiling.

MEM_OUT_OF_MEMORY There is insufficient memory.

MEM_WRONG_TASK pool belongs to a different task.

See also malloc, MemAlloc, MemAllocFS, MemFreePtr, MemReAllocPtr, MemSizePtr

Example #include <smrtheap.h>

/* StringPool initialized with MemPoolInit. */
extern MEM_POOL StringPool;
int DisplayError(char *msg, int num)
{
/* allocate buffer in which to format msg */
char *buf = (char *)MemAllocPtr(StringPool,
strlen(msg)+20, 0);
if (buf == NULL)
return FALSE; /* allocation failed */

/* format and display the message */
sprintf(buf, "Error #%d: %s.", num, msg);
MessageBox(GetFocus(), buf, NULL, MB_OK);

/* free the buffer */
MemFreePtr(buf);
return TRUE;
}

MemCheckPtr

Validates a memory pointer.

Syntax #include <smrtheap.h>
MEM_POINTER_STATUS MemCheckPtr(MEM_POOL pool,
void *mem);

Return value Returns MEM_POINTER_OK if the pointer is valid and currently in use, MEM_POINTER_FREE if mem is a valid entry in the pool but currently free, or MEM_POINTER_WILD if the pointer isn’t valid.

Description MemCheckPtr checks the memory block pointed to by mem, verifying that it is a valid entry of pool and that the entry is currently in use.

The value you supply for mem can be the result of any SmartHeap memory allocation API. To check handles allocated with MemAlloc, pass the pointer returned by MEM_REFERENCE. If you’re checking a pointer allocated by malloc or global operator new, pass MemDefaultPool for pool.

If you want to validate a pointer but don’t know or don’t care which pool it was allocated from, you may supply NULL for pool. MemCheckPtr will then verify that the pointer is a valid entry in some pool accessible from the current task.

An error is generated if the pointer isn’t a valid memory pool entry. Such errors are detected and reported in both the debug and non-debug versions of SmartHeap, but more information is reported by Debug SmartHeap.

Comments You can use this function to isolate dangling or wild pointers when you’re debugging your application. Note that if you pass a pointer that is a valid non-zero offset into a memory block allocated by SmartHeap, MemCheckPtr will report an error: you should pass only addresses returned by SmartHeap allocation functions to MemCheckPtr.

This function is intended for debugging only and should not be used in performance-critical situations. The function is slow for fixed-size blocks because the entire free-list must be searched to determine whether the block is free or in use.

Errors Error code Caused by

MEM_BAD_BLOCK A corrupt in-use block was detected.

MEM_BAD_FREE_BLOCK A corrupt free block was detected, or a free block has been written to.

MEM_BAD_MEM_POOL pool is invalid.

MEM_BAD_POINTER mem is an invalid pointer.

MEM_WRONG_TASK mem not owned by current task.

See also MemPoolCheck, MemPoolWalk, dbgMemProtectPtr

Example #include <smrtheap.h>

/* example list link structure */
typedef struct Link
{
int value;
struct Link *next;
} *PLINK;

/* check all links in a list for validity */
int CheckList(MEM_POOL LinkPool,
PLINK pLink)
{
/* traverse list, returning
immediately on error */
while (pLink)
if (MemCheckPtr(LinkPool, pLink))
pLink = pLink->next;
else
return FALSE;

return TRUE;
}

MemDefaultErrorHandler

This is SmartHeap’s default error-handling routine.

Syntax #include <smrtheap.h>
MEM_BOOL MEM_CALLBACK MemDefaultErrorHandler(
MEM_ERROR_INFO *errorInfo);

Return value Returns non-zero to retry (for example, because memory has been freed for the MEM_OUT_OF_MEMORY error) or zero if no attempt at retrying should be made.

Description MemDefaultErrorHandler provides default error handling for memory errors in your application if you do not use MemSetErrorHandler to establish a custom error handler. If you do define an error handler, you can call MemDefaultErrorHandler to handle error conditions you don’t want to handle specifically in your own handler.

You should never call MemDefaultErrorHandler except from your own error handler. In this case, you must pass through, without modification, the errorInfo parameter that SmartHeap passes to your error handler.

In the Runtime version of SmartHeap, the default error handler displays a prompt to the user interface with the options Ignore, Abort, and possibly Retry. The form of the prompt is system-dependent (see the Getting Started and Platform Guide). If the user chooses Abort, the current process or task is terminated. If the user chooses Ignore, SmartHeap returns from the failing function with an appropriate error code. If the user chooses Retry (for continuable errors), SmartHeap will try the operation again.

In the debug version of SmartHeap, you can control default error handling with dbgMemSetDefaultErrorOutput.

See the function MemSetErrorHandler for details on the MEM_ERROR_INFO structure.

See also MemSetErrorHandler, dbgMemSetSafetyLevel, dbgMemSetDefaultErrorOutput

Example #include <smrtheap.h>
#include <setjmp.h>

jmp_buf jbuf;

int main()
{
/* ... */

/* establish memory error handler */
MemSetErrorHandler(MyErrorHandler);

if (setjmp(jbuf) != 0)
/* if non-zero, we've thrown: clean up */
;

/* ... */
}

/* error handling callback procedure that
* calls MemDefaultErrorHandler if out of
* memory, or throws to top level for other
* types of errors
*/
MEM_BOOL MEM_CALLBACK MyErrorHandler( MEM_ERROR_INFO *errInfo)
{
/* if error code indicates an out-of-memory
condition, invoke default error handler
to prompt user to free memory,
otherwise throw to top level */
if (errInfo->errorCode == MEM_OUT_OF_MEMORY
&& MemDefaultErrorHandler(errInfo))
return TRUE;

longjmp(jbuf, 1);
}

MemDefaultPool

MemDefaultPoolBlockSizeFS, MemDefaultPoolFlags,
MemDefaultPoolPageSize,
MemInitDefaultPool, MemFreeDefaultPool

Global variables for memory pool used by malloc and new.

Syntax #include <smrtheap.h>

MEM_POOL MemDefaultPool;

unsigned short MemDefaultPoolBlockSizeFS;
unsigned MemDefaultPoolFlags;
unsigned MemDefaultPoolPageSize;

MEM_BOOL MemInitDefaultPool(void);
MEM_BOOL MemFreeDefaultPool(void);

Description MemDefaultPool is the default memory pool from which malloc, calloc, and new allocate. This pool is automatically created on the first call to malloc or new.

You can supply the value MemDefaultPool to any SmartHeap function that accepts a memory pool parameter. For example, you could pass it to MemPoolSize to determine the current size of the heap from which malloc allocates.

Important! Unless you’re sure malloc has already been successfully called, you should check the value of MemDefaultPool before referencing it. If it is NULL, then SmartHeap malloc has not yet been called. You can initialize the default pool explicitly if you wish by calling MemInitDefaultPool. You can call MemInitDefaultPool even if the default pool has already been initialized — in this case, MemInitDefaultPool simply returns the existing default pool.

Caution! You must not use MemPoolFree to free the default pool. You do not need to free MemDefaultPool, but if you want to for some reason, you must use MemFreeDefaultPool.

The compiler startup code can call malloc before your application gets control, so you may not have a chance to set attributes of the default pool before the first allocation. The global variables MemDefaultPoolPageSize and MemDefaultPoolBlockSizeFS solve this. You can define and initialize these at file scope. The first call to malloc then calls MemPoolSetPageSize and/or MemPoolSetBlockSizeFS after creating the default pool.

MemDefaultPoolFlags specifies flags that are passed to MemPoolInit when the default memory pool is initialized. Useful flag values are MEM_POOL_SERIALIZE for multi-threaded applications, and MEM_POOL_ZEROINIT for applications that desire memory returned by malloc and operator new to be zero-initialized.

See also malloc, calloc, new, MemPoolSetPageSize, MemPoolSetBlockSizeFS, MemPoolInit

Example #include <smrtheap.h>
#include <stdio.h>

/* initialize page size and fixed-size block
size of default memory pool at file scope*/
unsigned MemDefaultPoolPageSize = 8192;
unsigned short MemDefaultPoolBlockSizeFS = 32;

void main()
{
/* C RTL called malloc before main got
control, but the above variables are
already in effect in the default pool */
MEM_POOL_INFO info;
if (!MemDefaultPool)
MemInitDefaultPool();
MemPoolInfo(MemDefaultPool, NULL, info);

printf("def pool pageSize: %d;"
"blockSizeFS: %hd",
info.pageSize, info.blockSizeFS);
}

MemErrorUnwind

Mandatory call prior to error-handler non-local exit.

Syntax #include <smrtheap.h>

void MemErrorUnwind(void);

Return value None

Description MemErrorUnwind communicates to SmartHeap that your custom memory error handler will not return. If you establish an error handler that does a non-local exit (for example, longjmp or throw), you ­must call MemErrorUnwind immediately before the non-local exit.

SmartHeap detects per-thread recursive re-entry into the error handler (due to calling a SmartHeap function from a custom error handler that itself results in one or more errors). If you don’t call MemErrorUnwind before you longjmp out of your error handler, SmartHeap may report recursive re-entry to the error handler where there is none.

It is an error to call MemErrorUnwind other than from an error-handling callback established with MemSetErrorHandler. Likewise, it is an error to call MemErrorUnwind then proceed to return from the error handler.

See also MemSetErrorHandler

Example #include <smrtheap.h>
#include <setjmp.h>

jmp_buf jbuf;

MEM_BOOL MEM_CALLBACK MyErrorHandler(
MEM_ERROR_INFO *);

void main()
{
/* register with SmartHeap */
MemRegisterTask();

/* establish error handler */
MemSetErrorHandler(MyErrorHandler);

/* set up catch buffer; the longjmp from
MyErrorHandler will result in a
non-zero return from setjmp below */
for (;;) /* for loop causes restart */
if (setjmp(jbuf)) == 0)
break;
/* put an else clause here to clean up any
global state left dangling by error */

/* unregister with SmartHeap */
MemUnregisterTask();
}

/* Error-handler definition */
MEM_BOOL MEM_CALLBACK MyErrorHandler(
MEM_ERROR_INFO *errorInfo)
{
/* inform SmartHeap of pending
non-local exit */
MemErrorUnwind();

/* and throw back to top-level */
longjmp(jbuf, 1);
}

MemFix

Moves a handle-based block allocated by MemAlloc from the moveable to the fixed heap.

Syntax #include <smrtheap.h>

void *MemFix(MEM_HANDLE hMem);

Return value Returns a pointer to the memory block if successful, otherwise NULL.

Description MemFix is used to lock a handle-based memory block for a long period of time. If the block is currently on the moveable heap with a lock count of zero, MemFix moves the block to the fixed heap. If the block is already on the fixed heap, MemFix increments the block’s reference count.

It is an error to call MemFix on a block that is currently locked on the moveable heap, because locked blocks can’t be moved. Use MemUnlock to unlock the block before attempting to call MemFix.

SmartHeap will move the block back to the moveable heap when a subsequent MemUnfix call decreases the block’s reference count to zero.

Errors Error code Caused by

MEM_BAD_HANDLE hMem isn’t a valid memory handle.

MEM_DOUBLE_FREE hMem has been freed.

MEM_LOCK_ERROR hMem is a locked moveable block, or the block’s reference count has overflowed its limit of USHRT_MAX.

MEM_WRONG_TASK hMem allocated in a different task.

See also MemAlloc, MemFix, MemUnfix, MemHandle, MemIsMoveable, MemLockCount, MemUnlock

Example #include <smrtheap.h>

/* StringPool is a global variable that was
previously initialized with MemPoolInit. */
extern MEM_POOL StringPool;
MEM_HANDLE hStringTable = NULL;

/* initialize a string table */
int InitStringTable(int size)
{
/* initialize table to size entries */
hStringTable = MemAlloc(StringPool,
MEM_ZEROINIT | MEM_MOVEABLE,
sizeof(char *) * size);

return hStringTable != NULL;
}

/* perform lengthy operation on string table*/
int ProcessStrings(MEM_HANDLE hStringTable)
{
/* fix string table in memory */
char **pStringTable =
(char **)MemFix(hStringTable);
if (!pStringTable)
return FALSE;

/* ... perform lengthy operation,
directly referencing the pStringTable
pointer many times; the pool's moveable
heap may be compacted ... */

/* unfix the table */
MemFix(hStringTable);
return TRUE;
}

MemFree

Deallocates a memory block previously allocated by MemAlloc.

Syntax #include <smrtheap.h>

MEM_BOOL MemFree(MEM_HANDLE hMem);

Return value Returns non-zero if successful, otherwise zero.

Description MemFree frees the memory block identified by hMem.

Comments To ensure that you’re not generating leakage (a condition in which you fail to free memory that is no longer in use), you can use dbgMemReportLeakage in the debug version of SmartHeap to find unfreed blocks.

Errors Error code Caused by

MEM_BAD_HANDLE hMem isn’t a valid SmartHeap handle.

MEM_DOUBLE_FREE hMem was previously freed.

MEM_NOFREE hMem was marked as “no free” by dbgMemProtectPtr.

MEM_WRONG_TASK hMem was allocated in a different task.

See also free, MemAlloc, MemFreeFS, MemFreePtr, MemPoolFree

Example #include <smrtheap.h>
#define TRUE 1
#define FALSE 0

/* StringPool is a global variable that was
previously initialized with MemPoolInit. */
extern MEM_POOL StringPool;
MEM_HANDLE hStringTable = NULL;

/* initialize a string table */
int InitStringTable(int size)
{
/* initialize table to size entries */
hStringTable = MemAlloc(StringPool,
MEM_ZEROINIT | MEM_MOVEABLE,
sizeof(char *) * size);

return hStringTable != NULL;
}

int FreeStringTable()
{
if (hStringTable == NULL)
return FALSE;

/* free the buffer */
MemFree(hStringTable);
hStringTable = NULL;

return TRUE;
}

MemFreeFS

Deallocates a memory block previously allocated by MemAllocFS.

Syntax #include <smrtheap.h>

MEM_BOOL MemFreeFS(void *mem);

Return value Returns non-zero if successful, otherwise zero.

Description MemFreeFS frees the memory block pointed to by mem.

Comments If you wish to free all blocks in a given memory pool, you can simply call MemPoolFree rather than explicitly freeing each individual block. This is not only easier, but much faster and less error prone.

To ensure that you’re not generating leakage (a condition in which you fail to free memory that is no longer in use), you can use dbgMemReportLeakage in the debug version of SmartHeap to find unfreed blocks.

Errors Error code Caused by

MEM_BAD_POINTER mem is an invalid pointer.

MEM_DOUBLE_FREE mem was previously freed.

MEM_NOFREE mem was marked as “no free” by dbgMemProtectPtr.

MEM_WRONG_TASK mem was allocated in a different task.

See also free, MemAllocFS, MemFree, MemFreePtr, MemPoolFree

Example #include <smrtheap.h>

/* example list link structure */
typedef struct Link {
int value;
struct Link FAR *next;
} FAR *PLINK;

/* delete an element from a linked list,
returning the new list head */
PLINK DeleteLink(PLINK head, int val)
{
PLINK prev = NULL;
PLINK link = head;

/* search list for specified value */
while (link && link->value != val)
{
prev = link;
link = link->next;
}

if (link)
{ /* value was found: unlink */
if (prev)
prev->next = link->next;
else
head = link->next;

/* free the deleted link */
MemFreeFS(link);
}

return head;
}

int FreeList(MEM_POOL LinkPool)
{
/* Freeing pool frees all memory in it:
much faster and less error prone than
freeing each element individually! */
return MemPoolFree(LinkPool);
}

MemFreePtr

Deallocates a memory block.

Syntax #include <smrtheap.h>

MEM_BOOL MemFreePtr(void *mem);

Return value Returns non-zero if successful, otherwise zero.

Description MemFreePtr frees the memory block pointed to by mem. The block must have previously been allocated by SmartHeap calloc, malloc, realloc, ::operator new, MemAllocPtr, MemReAllocPtr, or MemAllocFS.

Comments If you wish to free all blocks in a given memory pool, you can call MemPoolFree rather than explicitly freeing each individual block. This is not only easier, but much faster and less error prone.

To ensure that you’re not generating leakage (a condition in which you fail to free memory that is no longer in use), you can use dbgMemReportLeakage in the debug version of SmartHeap to find unfreed blocks.

Errors Error code Caused by

MEM_BAD_POINTER mem is an invalid pointer.

MEM_DOUBLE_FREE mem was previously freed.

MEM_NOFREE mem was marked as “no free” by dbgMemProtectPtr.

MEM_WRONG_TASK mem was allocated in a different task.

See also free, MemAllocPtr, MemFree, MemFreeFS, MemPoolFree

Example #include <smrtheap.h>
#define TRUE 1
#define FALSE 0

/* StringPool is a global variable previously
that was initialized with MemPoolInit. */
extern MEM_POOL StringPool;

int DisplayError(char *msg, int num)
{
/* allocate buffer in which to format msg */
char *buf = (char *)MemAllocPtr(StringPool,
strlen(msg) + 20, FALSE);

/* return if allocation failed */
if (buf == NULL)
return FALSE;

/* format and display the message */
sprintf(buf, "Error #%d: %s.", num, msg);
MessageBox(GetFocus(), buf, NULL, MB_OK);

/* free the buffer */
MemFreePtr(buf);

return TRUE;
}

MemHandle

Returns the handle corresponding to a memory pointer returned by MemFix, MemLock, or MEM_REFERENCE.

Syntax #include <smrtheap.h>

MEM_HANDLE MemHandle(void *mem);

Return value Returns the memory handle corresponding to mem if successful, otherwise NULL.

Errors Error code Caused by

MEM_BAD_POINTER mem is an invalid pointer.

MEM_DOUBLE_FREE mem has been freed.

MEM_WRONG_TASK mem was allocated in a different task.

See also MemAlloc, MemFix, MemUnfix, MemLock, MemUnlock, MemFree

Example #include <smrtheap.h>
#define TRUE 1
#define FALSE 0

/* free a block allocated by MemAlloc,
given a pointer to such a locked block */
int MyFreePtr(void *mem)
{
/* obtain handle corresponding to ptr */
MEM_HANDLE hMem = MemHandle(mem);

/* return if no such handle */
if (hMem == NULL)
return FALSE;

/* unlock and free the handle */
MemUnlock(hMem);
MemFree(hMem);

return TRUE;
}

MemIsMoveable

Determines whether a block allocated with MemAlloc is currently in the fixed heap or the moveable heap.

Syntax #include <smrtheap.h>

MEM_BOOL MemIsMoveable(MEM_HANDLE hMem);

Return value The return value is non-zero for moveable blocks or zero for fixed blocks.

Description Each SmartHeap memory pool maintains two heaps for handle-based allocations: a moveable heap and a fixed heap. Blocks allocated with MEM_MOVEABLE are allocated from the moveable heap and have an initial lock count of zero. MemFix and MemUnfix move a block to the fixed heap or the moveable heap, respectively.

MemIsMoveable determines whether the block associated with a given handle is currently in the fixed heap or the moveable heap.

Comments If MemIsMoveable returns non-zero, this means that the block is on the moveable heap. However, the block can only be moved if its lock count is currently zero.

Errors Error code Caused by

MEM_BAD_HANDLE hMem isn’t a valid SmartHeap handle.

MEM_DOUBLE_FREE hMem has been freed.

MEM_WRONG_TASK hMem was allocated in a different task.

See also MemAlloc, MemFix, MemUnfix, MemLockCount

Example #include <smrtheap.h>
#define FALSE 0
#define TRUE 1

/* Force a block over to moveable heap.
Note: the technique illustrated here
is not recommended if the memory handle
is in use in multiple source files -- you
generally do not want to undo others'
locks (that's why SmartHeap provides
a reference count). */
int ForceMoveable(MEM_HANDLE hMem)
{
while (!MemIsMoveable(hMem))
if (MemUnfix(hMem) == MEM_UNLOCK_FAILED)
return FALSE;

return TRUE;
}

MemLock

Locks a moveable block allocated by MemAlloc.

Syntax #include <smrtheap.h>

void *MemLock(MEM_HANDLE hMem);

Return value Returns a pointer to the memory block if successful, otherwise NULL.

Description MemLock fixes the moveable memory block identified by hMem at a given address and increases its lock count by one. SmartHeap won’t move the block until its reference count is reduced to zero by subsequent calls to MemUnlock.

MemLock is invalid for fixed blocks, and will return NULL — to increment the lock count of blocks on the fixed heap, use MemFix.

Comments MEM_REFERENCE is recommended over MemLock in non-multi-threaded applications because it is faster and avoids creating a fixed sand-bar in the moveable heap. If you intend to lock a block for an extended period, use MemFix rather than MemLock.

Errors Error code Caused by

MEM_BAD_HANDLE hMem isn’t a valid SmartHeap handle.

MEM_DOUBLE_FREE hMem has been freed.

MEM_LOCK_ERROR hMem is a fixed block, or the block’s reference count has overflowed its limit of USHRT_MAX.

MEM_WRONG_TASK hMem was allocated in a different task.

See also MemAlloc, MemFix, MemUnfix, MemIsMoveable, MemLockCount, MemHandle, MemUnlock

Example #include <smrtheap.h>

/* StringPool is a global variable that was
previously initialized with MemPoolInit. */
extern MEM_POOL StringPool;
MEM_HANDLE hStringTable = NULL;

/* initialize a string table */
int InitStringTable(int size)
{
/* initialize table to size entries */
hStringTable = MemAlloc(StringPool,
MEM_ZEROINIT | MEM_MOVEABLE,
sizeof(char *) * size);

return hStringTable != NULL;
}

/* lock moveable block and update contents */
int SetString(int index, char *value)
{
/* lock table in memory */
char * *pStringTable =
(char * *)MemLock(hStringTable);

if (!pStringTable)
return FALSE;

/* update string table entry */
pStringTable[index] = value;

/* unlock the table */
MemUnlock(hStringTable);
return TRUE;
}

MemLockCount

Returns the lock count of a handle-based memory block allocated with MemAlloc.

Syntax #include <smrtheap.h>

unsigned MemLockCount(MEM_HANDLE hMem);

Return value Returns the lock count for moveable blocks or the fix count for fixed blocks.

Description SmartHeap fixed-handle-based blocks always have a lock count of at least one. If MemUnfix is used to decrease a fixed block’s lock count, the block is shifted to the moveable heap.

Moveable memory blocks are actually moveable only if their lock count is zero (the initial lock count is zero for blocks allocated as MEM_MOVEABLE).

You can use the MemIsMoveable function to determine whether a block is currently on the fixed or the moveable heap.

Errors Error code Caused by

MEM_BAD_HANDLE hMem isn’t a valid SmartHeap handle.

MEM_DOUBLE_FREE hMem has been freed.

MEM_WRONG_TASK hMem was allocated in a different task.

See also MemAlloc, MemFix, MemUnfix, MemIsMoveable, MemLock, MemUnlock

Example #include <smrtheap.h>

/* determine whether memory block is locked */
int IsLocked(MEM_HANDLE hMem)
{
return MemLockCount(hMem) != 0;
}

MemPoolAttachShared

Maps a shared memory pool into the current process.

Syntax #include <smrtheap.h>

MEM_POOL MemPoolAttachShared(MEM_POOL pool,
const char *name);

Return value Returns a memory pool if successful otherwise NULL.

Description MemPoolAttachShared maps the pool identified by either pool or name into the current process.

If you supply a non-NULL name parameter, SmartHeap ignores the pool parameter. In that case, the name parameter must specify a name that was previously passed to MemPoolInitNamedShared or MemPoolInitNamedSharedEx in another process.

If you supply a NULL name parameter, the pool parameter must specify the address returned by MemPoolInit[FS] (with flags specifying MEM_POOL_SHARED), in another process. In this case, you must use some form of IPC to communicate the pool address from one process to the other. Using a NULL name parameter for MemPoolAttachShared is supported only for OS/2 named shared pools.

Beginning in SmartHeap 3.1, you can use MemPoolInitNamedShared or MemPoolInitNamedSharedEx instead of MemPoolAttachShared. If the named shared pool already exists, MemPoolInitNamedShared[Ex] performs the same function as MemPoolAttachShared. Use this technique if you aren’t sure which process will create the shared pool first — SmartHeap automatically serializes all calls to MemPoolInitNamedShared[Ex].

Comments This function is currently available only in the Win32, OS/2, and UNIX versions of SmartHeap. For Win32 and UNIX, only named shared pools are supported.

See also MemPoolInit, MemPoolInitNamedShared, MemPoolInitNamedSharedEx

Example #include <smrtheap.h>

/* set up platform-specific shared pool name */
#ifdef __OS2__
#define SHR_POOL_NAME "\\SHAREMEM\\SHTEST"
#define SHR_POOL_SIZE 0
#else
#include <sys/types.h>
#include <sys/ipc.h>
#define SHR_POOL_NAME \
(const char *)ftok("tclient.c", 'a')
#define SHR_POOL_SIZE 8192
#endif

/* server process: create shared pool */
void main()
{
MEM_POOL namedPool =
MemPoolInitNamedShared(SHR_POOL_NAME,
SHR_POOL_SIZE, 0);

/* wait for server process to allocate
from the shared pool */
while (MemPoolCount(namedPool) == 0)
; /* should sleep here */
/* free pool from client process */
MemPoolFree(namedPool);
}

/* client process: attach shared pool */
void main()
{
MEM_POOL pool =
MemPoolAttachShared(SHR_POOL_NAME, NULL);

/* allocate from pool */
MemAllocPtr(pool, 1, 0);

/* free pool from server process */
MemPoolFree(pool);
}

MemPoolCheck

Validates all blocks in a memory pool and reports any problems discovered.

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolCheck(MEM_POOL pool);

Return value Returns non-zero if the pool is successfully validated, or zero if error(s) were detected.

Description MemPoolCheck first verifies that pool is a valid memory pool, then traverses each memory block in the pool, whether free or in use, and reports any errors encountered. If the function detects a problem in the pool, the error handler is invoked with the address where the corruption was detected.

This function is useful in diagnosing memory overwrites that your program may be causing. MemPoolCheck may be used with all SmartHeap memory pools in both the Debug and Runtime SmartHeap.

To validate the memory pool used by malloc and operator new, pass the value MemDefaultPool for pool.

When the debug version of SmartHeap is used with the safety level set to MEM_SAFETY_DEBUG, MemPoolCheck is called automatically at each SmartHeap entry point.

Comments To isolate bogus memory writes, place calls to MemPoolCheck at strategic points in your program during debugging.

Errors Error code Caused by

MEM_BAD_BLOCK MemPoolCheck detected a block in pool whose header information has been overwritten.

MEM_BAD_FREE_BLOCK MemPoolCheck detected a free block within pool that has been written into since it was freed.

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also MemCheckPtr, MemPoolWalk, MemSetErrorHandler, dbgMemSetSafetyLevel, dbgMemPoolSetCheckFrequency, dbgMemSetGuardSize, dbgMemSetGuardFill, dbgMemSetFreeFill, dbgMemSetInUseFill

Example #include <smrtheap.h>

/* check heap after sprintf to be sure
we haven't overwritten buf */
int SafeSprintf(char *buf, char *format,
va_list argList)
{
int result = vsprintf(buf, format, argList);

if (!MemPoolCheck(MemDefaultPool))
{
MessageBox(GetFocus(),
"Memory overwritten by sprintf",
NULL, MB_OK);
return 0;
}

return result;
}

MemPoolCount

Returns the number of blocks currently in use in a memory pool.

Syntax #include <smrtheap.h>

unsigned long MemPoolCount(MEM_POOL pool);

Return value Returns the net number of allocations from pool, that is, the count of all allocations minus the count of all deallocations if successful, or MEM_ERROR_RET if pool is invalid.

Description If you use a memory pool exclusively for a single data structure, such as a linked list, MemPoolCount gives you a quick way to determine an element count without computing or maintaining this yourself.

SmartHeap maintains an allocation count for each page in a pool. It uses this to return free pages to the operating system when their allocation count is reduced to zero. The MemPoolCount function returns the sum of the allocation counts for all of the pages that are owned by the specified memory pool.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also MemPoolShrink, MemPoolSize, MemPoolWalk

Example #include <smrtheap.h>

struct Link {
int val;
struct Link *next;
};
struct List {
struct Link *head;
MEM_POOL pool;
};

/* use fixed-size pool for list elements */
int InitList(struct List *list)
{
list->head = NULL;
list->pool =
MemPoolInitFS(sizeof(struct Link), 10, 0);

return link->pool != NULL;
}

/* list length equals pool block count */
unsigned long ListLength(struct List *list)
{
return MemPoolCount(list->pool);
}

MemPoolFirst

Begins enumeration of SmartHeap memory pools.

Syntax #include <smrtheap.h>

MEM_POOL_STATUS MemPoolFirst(
MEM_POOL_INFO *info, MEM_BOOL bAllTasks);

Return value Returns MEM_POOL_OK if the first pool is okay. Returns MEM_POOL_CORRUPT if the pool has been corrupted or if the pointer specified in info is invalid. Returns MEM_POOL_END if no memory pools have been created.

Description MemPoolFirst returns information about the first SmartHeap memory pool. Use MemPoolNext to continue the enumeration and find information about subsequent memory pools.

Windows 16-bit In the 16-bit Windows version of SmartHeap, if bAllTasks is:

bAllTasks is ignored on all other platforms.

The info parameter is a pointer to the following structure:

typedef struct {
MEM_POOL pool;
MEM_BLOCK_TYPE type;
unsigned short blockSizeFS;
unsigned short smallBlockSize;
unsigned pageSize;
unsigned long floor;
unsigned long ceiling;
unsigned flags;
MEM_ERROR_FN errorFn;
} MEM_POOL_INFO;

typedef enum {
MEM_FS_BLOCK = 0x0001u,
MEM_VAR_MOVEABLE_BLOCK = 0x0002u,
MEM_VAR_FIXED_BLOCK = 0x0004u
} MEM_BLOCK_TYPE;

The type field of MEM_POOL_INFO is a disjunctive combination of MEM_BLOCK_TYPE flags. This field indicates what types of blocks are currently allocated in the pool.

Type blockSizeFS, smallBlockSize, pageSize, floor, and ceiling fields are the values established by MemPoolSetBlockSizeFS, MemPoolSetSmallBlockSize, MemPoolSetPageSize, MemPoolSetFloor, and MemPoolSetCeiling, respectively.

The flags field is the value that was passed as the flags parameter to MemPoolInit or MemPoolInitFS when the pool was created. The errorFn is the value established by the MemSetErrorHandler function.

Errors Error code Caused by

MEM_BAD_MEM_POOL A memory pool corruption was encountered while enumerating pools.

See also MemPoolInfo, MemPoolNext

Example #include <smrtheap.h>

/* return to the operating system
all memory not in use */
int ShrinkAllPools()
{
MEM_POOL_INFO info;
MEM_POOL_STATUS status;

status = MemPoolFirst(&info, 0);

while (status == MEM_POOL_OK) {
MemPoolShrink(info.pool);
status = MemPoolNext(&info, 0);
}
return (status != MEM_POOL_CORRUPT);
}

MemPoolFree

Deallocates all memory in a memory pool.

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolFree(MEM_POOL pool);

Return value Returns non-zero if successful, otherwise zero.

Description MemPoolFree returns all memory allocated from pool to the operating system and frees the pool data structure. You can use this function as an alternative to explicitly freeing each individual block in a pool. This is not only easier but also much faster and less error prone than freeing individual blocks.

Caution! You must not use MemPoolFree to free the default memory pool, MemDefaultPool. You do not need to free the default memory pool, but if you want to for some reason, use MemFreeDefaultPool.

Comments In virtual memory environments, using MemPoolFree greatly reduces swapping when compared with freeing blocks individually. The pages on which the freed blocks reside can be returned to the operating system without being referenced, and they won’t be swapped in if they aren’t currently resident.

MemUnregisterTask frees all pools owned by the current task or process.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also MemPoolInit, MemPoolInitFS, MemPoolShrink, MemUnregisterTask

Example #include <smrtheap.h>

/* example list link structure */
struct Link {
int value;
struct Link *next;
};

/* delete an element from a linked list,
returning the new list head */
struct Link *DeleteLink(struct Link *head,
int val)
{
struct Link *prev = NULL;
struct Link *link = head;

/* search list for specified value */
while (link && link->value != val)
{
prev = link;
link = link->next;
}

if (link)
{ /* value was found: unlink */
if (prev)
prev->next = link->next;
else
head = link->next;

/* free the deleted link */
MemFreeFS(link);
}
return head;
}

int FreeList(MEM_POOL LinkPool)
{
/* Freeing pool frees all memory:
much faster and less error prone than
freeing each element individually! */
return MemPoolFree(LinkPool);
}

MemPoolInfo

Returns information about a memory pool, given either a pool or a pointer.

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolInfo(MEM_POOL pool, void *ptr,
MEM_POOL_INFO *info);

Return value Returns non-zero if successful, otherwise zero.

Description MemPoolInfo returns information about a memory pool. To retrieve this information, you can pass the function a memory pool, a pointer, or both.

If you pass a NULL pool parameter and a non-NULL ptr parameter, then information about the pool owning the supplied pointer is returned.

The info parameter is a pointer to the following structure:

typedef struct {
MEM_POOL pool;
MEM_BLOCK_TYPE type;
unsigned short blockSizeFS;
unsigned short smallBlockSize;
unsigned pageSize;
unsigned long floor;
unsigned long ceiling;
unsigned flags;
MEM_ERROR_FN errorFn;
} MEM_POOL_INFO;

typedef enum {
MEM_FS_BLOCK = 0x0001u,
MEM_VAR_MOVEABLE_BLOCK = 0x0002u,
MEM_VAR_FIXED_BLOCK = 0x0004u
} MEM_BLOCK_TYPE;

The type field of MEM_POOL_INFO is a disjunctive combination of MEM_BLOCK_TYPE flags. This field indicates what types of blocks are currently allocated in the pool.

The blockSizeFS, smallBlockSize, pageSize, floor, and ceiling fields have the values set by MemPoolSetBlockSizeFS, MemPoolSetSmallBlockSize, MemPoolSetPageSize, MemPoolSetFloor, and MemPoolSetCeiling, respectively.

The flags field is the value that was passed as the flags parameter to MemPoolInit or MemPoolInitFS when the pool was created. The errorFn field is the value established by the function MemSetErrorHandler.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is an invalid memory pool.

MEM_BAD_POINTER ptr is an invalid memory block, or one not owned by pool.

MEM_DOUBLE_FREE ptr was previously freed.

MEM_WRONG_TASK pool belongs to a different task.

See also MemPoolCount, MemPoolFirst, MemPoolNext, MemPoolSize

Example #include <smrtheap.h>

MEM_POOL PoolOfPtr(void *ptr)
{
MEM_POOL_INFO info;

if (MemPoolInfo(NULL, ptr, &info))
return info.pool;
else
return NULL;
}

MemPoolInit

Creates a memory pool for subsequent allocations.

Syntax #include <smrtheap.h>

MEM_POOL MemPoolInit(unsigned flags);

Return value Returns a new memory pool if successful, otherwise NULL.

Description MemPoolInit creates a new memory pool from which individual memory blocks are allocated. If you use only malloc or C++ operator new, you do not need to call this function. A default memory pool, MemDefaultPool, is automatically created during the first call to malloc or new from each task or process (or you may create it explicitly with MemInitDefaultPool). If you use any other SmartHeap memory-allocating functions, you need to create a memory pool with this function or with MemPoolInitFS before you allocate memory.

To construct the flags parameter, bitwise OR one or more of the following values:

MEM_POOL_DEFAULT

Create a pool with default characteristics.

MEM_POOL_SERIALIZE

Make pool thread-safe.

MEM_POOL_SHARED

Allocates an unnamed shared memory pool. Unnamed shared pools are supported only in OS/2 and 16-bit Windows.

MEM_POOL_VIRTUAL_LOCK

Memory allocated from pool is locked in physical memory. Use only for memory that is referenced at interrupt time.

MEM_POOL_ZEROINIT

For use with default pool only. Memory returned by malloc and operator new is zero-initialized. Supported only for 16-bit and 32-bit Windows.

The flags parameter specifies platform-specific attributes for all memory allocated from the pool.

Comments SmartHeap memory pools provide a mechanism for working with a group of related allocations. A memory pool establishes a working set, occupying a minimal number of pages to provide the requested allocations. Related allocations thus tend to be swapped in or out of physical memory together, making memory accesses more efficient.

Windows 16-bit In the 16-bit Windows version of SmartHeap, memory pools are either owned by the calling task, or they’re allocated as shareable under Windows 3.x rules (GMEM_SHARE). Use the MEM_POOL_SHARED flag to create a shared memory pool. Shared memory pools are owned by the Windows module (EXE or DLL) that called MemPoolInit to create the pool. SmartHeap automatically frees shared memory pools upon termination of the DLL, or EXE instance, that created the pool.

In 16-bit Windows, MEM_POOL_DEFAULT has special meaning. If you use this flag when you call MemPoolInit from:

Errors Error code Caused by