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

MEM_BAD_FLAGS Invalid flags parameter.

MEM_OUT_OF_MEMORY There is insufficient memory.

See also MemAlloc, MemAllocPtr, MemPoolFree, MemPoolInitFS, MemPoolSetBlockSizeFS, MemPoolSetPageSize

Example #include <smrtheap.h>

/* create a pool for variable-size strings */
MEM_POOL StringPool;
int InitStringPool()
{
StringPool = MemPoolInit(MEM_POOL_DEFAULT);
return StringPool != NULL;
}

MemPoolInitFS

Creates and initializes a memory pool for subsequent allocations of fixed-size blocks.

Syntax #include <smrtheap.h>

MEM_POOL MemPoolInitFS(unsigned short blockSize,
unsigned long blockCount, unsigned flags);

Return value Returns a memory pool if successful, otherwise zero.

Description MemPoolInitFS creates a new memory pool from which fixed-size memory blocks are to be allocated. You must create a memory pool before allocating fixed-size memory blocks.

The blockSize parameter specifies the size of fixed-size memory blocks to be allocated from this pool. You can’t change the block size after the first allocation. SmartHeap may round the block size up for alignment — use MemPoolInfo or MemSizePtr to determine the actual block size.

The blockCount parameter specifies the initial number of blocks to allocate in the memory pool — the pool will grow beyond this if necessary to satisfy allocation requests.

See MemPoolInit for details on the flags parameter.

Comments MemPoolInitFS is equivalent to calling the combination of MemPoolInit, MemPoolSetBlockSizeFS, and MemPoolPreAllocate.

Errors Error code Caused by

MEM_ALLOC_ZERO blockSize is zero.

MEM_BAD_FLAGS Invalid flags parameter.

MEM_BLOCK_TOO_BIG blockSize exceeds page size.

MEM_OUT_OF_MEMORY There is insufficient memory.

See also MemAllocFS, MemPoolFree, MemPoolInit, MemPoolPreAllocate, MemPoolSetBlockSizeFS

Example #include <smrtheap.h>

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

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

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

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

/* free entire list */
int FreeList(MEM_POOL pool)
{ /* Freeing pool is faster and less error
prone than freeing each element! */
return MemPoolFree(pool);
}

MemPoolInitNamedShared

Creates a named shared memory pool.

Syntax #include <smrtheap.h>

MEM_POOL MemPoolInitNamedShared(
const char *name, unsigned long size,
unsigned flags);

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

Description MemPoolInitNamedShared creates a memory pool that can be shared between processes.

The name parameter must be a valid operating system shared memory identifier. For Win32, name can be any character string that does not contain the backslash (\) character. For OS/2, this is a file system path name with the prefix "\SHAREMEM\". For UNIX, use ftok() to create a key, and cast the result to (const char *).

The flags parameter implicitly includes MEM_POOL_SHARED and MEM_POOL_SERIALIZE. For other flag values, see MemPoolInit.

For Win32, size specifies the maximum size of the pool. In this case, size bytes of address space are reserved when the pool is allocated, but memory is committed based on actual allocation requests. For OS/2, the size parameter is ignored because, on that platform, shared memory pools can grow dynamically, limited only by available memory. For UNIX, size specifies the total size of the pool, which is fixed at initialization.

Important See the section on using shared memory in the Getting Started and Platform Guide for additional platform-specific details on using SmartHeap shared memory.

Comments This function is currently available only in the Win32, OS/2, and UNIX versions of SmartHeap.

Shared memory pools are always serialized with inter-process synchronization mutual exclusion. You can concurrently allocate blocks from a shared pool from multiple processes with complete safety.

Errors Error code Caused by

MEM_BAD_FLAGS Invalid flags parameter.

MEM_OUT_OF_MEMORY There is insufficient memory, name is an invalid operating system shared memory identifier, or an error occurred creating the underlying shared memory object or mutex object.

See also MemPoolAttachShared, MemPoolInit, 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
#elif defined(__WIN32__)
#define SHR_POOL_NAME "SHTEST"
#define SHR_POOL_SIZE 8192
#elif defined(unix)
#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);
}

MemPoolInitNamedSharedEx

Creates a named shared memory pool at specified address, in specified processes, and/or with specified security attributes.

Syntax #include <smrtheap.h>

MEM_POOL MemPoolInitNamedSharedEx(void *addr,
unsigned pidCount, unsigned long *pids,
void *security, const char *name,
unsigned long size, unsigned flags);

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

Description MemPoolInitNamedSharedEx creates a memory pool that can be shared between processes.

The name, flags, and size parameters are the same as for MemPoolInitNamedShared.

Specify addr as non-NULL as a hint to SmartHeap about a suitable location to map the pool. If addr is NULL, SmartHeap and/or the operating system will choose an address to map the shared pool.

Specify pidCount as non-zero to supply an array of process IDs that SmartHeap should search. If pidCount is non-zero, pids must point to an array of pidCount elements, each of which is a valid process identifier at the time the shared pool is created (for Win32, process identifiers are returned by GetCurrentProcessId). If pidCount is zero, the pids parameter is ignored and no processes are searched.

Caution In the Win32 version of SmartHeap, the new memory pool is automatically mapped into the address space of each process identified in pids only if you use the SmartHeap DLL. If you statically link SmartHeap with your application, SmartHeap will search pids to find a suitable address for the shared pool, but it will not immediately map the pool into each process. This is an important distinction in NT, since shared memory is not guaranteed to be mapped to the same address in each process. If you statically link SmartHeap into your NT app, the address chosen for the pool may become in use in another process before that process has a chance to call MemPoolAttach, causing MemPoolAttach to fail in that process.

The security parameter is passed through to the operating system and specifies security attributes for the shared memory pool. You can specify NULL for default security attributes.

Important See the section on using shared memory in the Getting Started and Platform Guide for additional platform-specific details on using SmartHeap shared memory.

Comments This function is currently available only in the Win32 version of SmartHeap.

Shared memory pools are always serialized with inter-process synchronization mutual exclusion. You can concurrently allocate blocks from a shared pool from multiple processes with complete safety.

Errors Error code Caused by

MEM_BAD_FLAGS Invalid flags parameter.

MEM_OUT_OF_MEMORY There is insufficient memory, name is an invalid operating system shared memory identifier, pids specifies one or more invalid process IDs, or an error occurred creating the underlying shared memory object or mutex object..

See also MemPoolAttachShared, MemPoolInit

Example #include <smrtheap.h>

#define SHR_POOL_NAME "SHTEST"
/* create a shared pool, and map into the
* processes whose ID’s are specified on the
* command line
*/
void main(int argc, char *argv[])
{
MEM_POOL pool;
void *ptr;
unsigned long i;
unsigned long addr = 0;
unsigned long pidCount = 0;
unsigned long pids[MAX_PIDS];

if (argc > 1)
addr = strtoul(argv[1], NULL, 0);
if (argc > 2)
pidCount = strtoul(argv[2], NULL, 0);

i = pidCount;

if (pidCount && argc < pidCount+3)
{
parmError:
printf("\nusage: tshared [<addr>]"
"[<pidCount> <pid1> <pid2>...]\n");
return;
}

while (i--)
{
if ((pids[i] = strtoul(argv[i+3], NULL, 0))
== 0)
goto parmError;
}

printf("allocating 3MB named shared pool...\n");
pool = MemPoolInitNamedSharedEx((void *)addr,
pidCount, pids, NULL, SHR_POOL_NAME,
0x300000, 0);
}

MemPoolInitRegion

Creates a memory pool within a user-supplied memory region.

Note MemPoolInitRegion is a new API present only in SmartHeap 3.3 and higher.

Syntax #include <smrtheap.h>

MEM_POOL MemPoolInitRegion(void *addr,
unsigned long size, unsigned flags);

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

Description MemPoolInitRegion creates a memory pool in memory space that you allocate and pass to the function.

The name, flags, and size parameters are the same as for MemPoolInitNamedShared.

Specify addr as the address of a memory region you have allocated within which SmartHeap is to manage the pool’s memory. SmartHeap will manage the pool within the contiguous region beginning at addr and ending at addr plus size.

Specify size as the maximum number of bytes of memory SmartHeap can use for the pool. The size value you specify must not exceed the size of the allocated region beginning at addr.

Supply MEM_POOL_SERIALIZE if serialization of heap calls is desired for the pool. If MEM_POOL_SHARED is supplied, SmartHeap uses shared memory serialization (mutex for Win32), otherwise SmartHeap uses a process-private serialization (critical section for Win32). Unlike a standard memory pool, MEM_POOL_SERIALIZE is not required nor implied if MEM_POOL_SHARED is supplied alone — in this case, you must serialize allocations from each process that maps the pool.

Windows 32-bit In the 32-bit Windows version of SmartHeap, the supplied region must be reserved but need not be committed. It can be either private or shared (memory mapped file). If the memory region is within a memory mapped file, MEM_POOL_SHARED must be supplied with flags. SmartHeap will commit or decommit sub-ranges of address space within the region to dynamically grow or shrink the pool based on allocation requests. (SmartHeap will decommit only for private pools because Win32 does not support decommitting portions of a memory mapped file. For this reason, the entire region should be initially uncommitted for memory mapped file regions, since Win32 does support commit for portions of a memory mapped file.)

Call MemPoolFree to release pools created by MemPoolInitRegion — this will close serialization objects and, for private pools, decommit the entire address range. The caller is responsible for actually freeing the memory.

Comments This function is currently available only in the Win32 version of SmartHeap.

MemPoolInitRegion rounds addr up to the nearest 4K boundary and truncates size beginning at the next 64K boundary after addr to the nearest 64K multiple; the head and tail of the region, if any, are not used, so to avoid wasting memory, supply a 4K-aligned and 64K-granular region. For example, if addr and size are specified as 0x02000800 and 1040K, respectively, then addr will be rounded up to 0x02001000 and size truncated to 978K.

Errors Error code Caused by

MEM_BAD_FLAGS Invalid flags parameter.

MEM_OUT_OF_MEMORY There is insufficient memory.

See also MemPoolInit, MemPoolInitShared

Example #include <smrtheap.h>

/* create a memory pool with default characteristics
* within static memory space
*/

char poolBuf[512 * 1024] /* 512K buffer for pool */

MEM_POOL createStaticPool()
{
return MemPoolInitRegion(&poolBuf, sizeof(poolBuf),
MEM_POOL_DEFAULT);
}

MemPoolLock

Locks a memory pool for exclusive access within current thread.

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolLock(MEM_POOL pool);

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

Description MemPoolLock increments the lock count of a given memory pool. When the lock-count is non-zero, the current thread has exclusive access to the memory pool until MemPoolUnlock reduces the lock count back to zero. When a thread has a pool locked, all SmartHeap calls from other threads that involve this memory pool, or memory blocks within this pool, are blocked.

Important! MemPoolLock has no effect unless the MEM_POOL_SERIALIZE flag was supplied at the time the memory pool was created.

Also Important! Each call to MemPoolLock must be balanced with a later call to MemPoolUnlock to prevent operations on the pool from being blocked indefinitely in other threads.

Comments This function is useful in conjunction with MemPoolWalk, since MemPoolWalk requires exclusive access its pool between calls. You can also use MemPoolLock if you want to prevent a thread from blocking due to heap serialization, for example, because it is a real-time thread.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also MemPoolUnlock, MemPoolWalk

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

/* Search all blocks in a memory pool for
the specified character string. */
char *SearchPool(MEM_POOL pool, char *str)
{
MEM_POOL_ENTRY entry;
unsigned len = strlen(str) + 1;
char *result = NULL;

entry.entry = NULL;

MemPoolLock(pool); /* lock pool while enumerating*/

while (MemPoolWalk(pool, &entry) == MEM_POOL_OK)
if (entry.isInUse && len <= entry.size
&& memcmp(entry.entry, str,len) == 0)
result = (char *)entry.entry;

MemPoolUnlock(pool);

return result;
}

MemPoolNext

Continues enumeration of SmartHeap memory pools.

Syntax #include <smrtheap.h>

MEM_POOL_STATUS MemPoolNext(
MEM_POOL_INFO *info, MEM_BOOL bAllTasks);

Return value Returns MEM_POOL_OK if the next 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 all memory pools have been enumerated.

Description MemPoolNext returns information about the next SmartHeap memory pool. Use MemPoolFirst to begin the enumeration.

Windows 16-bit In the 16-bit Windows version of SmartHeap, if bAllTasks is non-zero, all memory pools are enumerated. If it is zero, only pools owned by the current task (for EXE) or module (for DLL), are enumerated. bAllTasks is ignored on 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.

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 to the MemPoolInit/MemPoolInitFS call that created the pool.

The errorFn field is the value established by the MemSetErrorHandler function.

Caution! You must not create or destroy any memory pools between calls to MemPoolNext (even from a different thread).

Errors Error code Caused by

MEM_BAD_MEM_POOL A corrupted memory pool was detected.

See also MemPoolFirst, MemPoolInfo

Example #include <smrtheap.h>

/* free all SmartHeap 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);
}

MemPoolPreAllocate

Reserves memory for subsequent allocations.

Syntax #include <smrtheap.h>

unsigned long MemPoolPreAllocate(MEM_POOL pool,
unsigned long size, MEM_BLOCK_TYPE type);

Return value Returns the number of bytes actually added to the memory pool if successful, otherwise MEM_ERROR_RET.

Description MemPoolPreAllocate reserves up to size bytes of memory from the operating system and adds this memory to pool, initializing it as free blocks of type type.

If size exceeds currently available memory, the function reserves as much as can be allocated from the operating system.

The type parameter has the following type:

typedef enum {
MEM_FS_BLOCK,
MEM_VAR_MOVEABLE_BLOCK,
MEM_VAR_FIXED_BLOCK
} MEM_BLOCK_TYPE;

Only one of the above block types can be specified in a given call to MemPoolPreAllocate.

Comments MemPoolPreAllocate is useful for incurring the overhead of the system calls and free block initialization in advance of a performance-sensitive and memory-intensive operation.

Another use for MemPoolPreAllocate is to ensure in advance that your application has the memory it requires to complete an operation. Use MemPoolSetFloor in conjunction with this function to ensure that the memory you reserve isn’t returned to the operating system (see example).

Errors Error code Caused by

MEM_ALLOC_ZERO type is MEM_FS_BLOCK, and pool has a block size of zero.

MEM_BAD_MEM_POOL Invalid pool parameter.

MEM_EXCEEDED_CEILING Adding size bytes to current pool size would exceed ceiling established by MemPoolSetCeiling.

MEM_OUT_OF_MEMORY There is insufficient memory.

See also MemPoolSetFloor, MemPoolInitFS, MemPoolSize

Example #include <smrtheap.h>

#define K(x) ((x) * 1024L)
struct Link {
int val;
struct Link *next;
};

/* reserve fixed-size memory for 1000 Link's,
plus 64K for variable-size blocks, then
set a floor to ensure that this memory is
not returned to the operating system
*/
int ReserveMem(MEM_POOL pool)
{
MemPoolPreAllocate(pool,
1000*sizeof(struct Link), MEM_FS_BLOCK);
MemPoolPreAllocate(pool,
K(64), MEM_VAR_FIXED_BLOCK);
MemPoolSetFloor(pool,
K(64) + 1000*sizeof(struct Link));
}

MemPoolPreAllocateHandles

Reserves handles for subsequent handle-based allocations.

Syntax #include <smrtheap.h>

unsigned long MemPoolPreAllocateHandles(
MEM_POOL pool, unsigned long handleCount);

Return value Returns the number of handle table entries actually allocated if pool is valid, otherwise MEM_ERROR_RET.

Description MemPoolPreAllocateHandles reserves up to handleCount handle table entries in the handle table of pool. The function may allocate fewer handle table entries if there is insufficient memory.

Each memory pool has its own handle table, and each handle-based allocation (MemAlloc) uses one handle table entry.

If you do not call MemPoolPreAllocateHandles, SmartHeap will automatically add handle table entries as needed. When SmartHeap adds handle table entries automatically, it allocates them in discontiguous blocks of a platform-specific size (often 4K). If you call MemPoolPreAllocateHandles, the handle table will be in one contiguous block large enough to accommodate exactly the number of handles you specify.

Comments If you know in advance how many handles you will allocate, you can call this function before the first call to MemAlloc.

For Macintosh programmers, a SmartHeap handle table is like a master pointer block in the Mac memory manager. MemPoolPreAllocateHandles is like the Mac MoreMasters routine.

Errors Error code Caused by

MEM_OUT_OF_MEMORY There is insufficient memory.

See also MemAlloc, MemPoolCount

Example #include <smrtheap.h>

/* program will allocate 20,000 handle-based
blocks, so reserve exactly that many
handle-table entries
*/
void main()
{
int i;
MEM_POOL pool=MemPoolInit(MEM_POOL_DEFAULT);

MemPoolPreAllocateHandles(pool, 20000)

for (i = 0; i < 20000; i++)
MemAlloc(pool, 0, 1);

MemPoolFree(pool);
}

MemPoolSetBlockSizeFS

Establishes the size of fixed-size blocks in a memory pool.

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolSetBlockSizeFS(MEM_POOL pool,
unsigned short blockSizeFS);

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

Description Every memory pool has a block size for fixed-size blocks. The MemPoolSetBlockSizeFS function establishes a pool’s fixed-size block size. MemAllocFS allocates blocks of this size.

It is an error to call MemPoolSetBlockSizeFS when one or more fixed-size blocks is currently allocated — such a call has no effect. It is also an error to set blockSizeFS larger than a pool’s current page size.

Note Beginning in SmartHeap 3.0, MemPoolSetBlockSizeFS has no effect on the SmartHeap variable-size APIs such as malloc, operator new, and MemAllocPtr. MemPoolSetBlockSizeFS affects only MemAllocFS. This is because SmartHeap 3.0 introduces a new algorithm for managing small blocks (those less than 256 bytes, by default) that does not incur the speed/space tradeoff that MemAllocFS with a large size does.

In SmartHeap 3.1 and higher, MemPoolSetSmallBlockSize allows you to tune the small block threshold if the default of 256 bytes is not a suitable threshold for your application.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_BLOCK_TOO_BIG blockSizeFS is larger than page size (see MemPoolSetPageSize).

MEM_WRONG_TASK pool belongs to a different task.

See also MemDefaultPoolBlockSizeFS, MemPoolInfo, MemPoolInitFS, MemPoolSetPageSize, MemPoolSetSmallBlockSize, MemSizePtr

Example #include <smrtheap.h>

/* set pool's fixed-size block size to 16 bytes */
int InitBlockSizeFS(MEM_POOL pool)
{
return MemPoolSetBlockSizeFS(pool, 16);
}

MemPoolSetCeiling

Establishes the maximum size of a memory pool.

Syntax #include <smrtheap.h>

unsigned long MemPoolSetCeiling(MEM_POOL pool,
unsigned long ceiling);

Return value Returns the previous ceiling value of pool if successful, otherwise MEM_ERROR_RET.

Description MemPoolSetCeiling establishes the maximum number of bytes of memory that pool can consume.

By default, pools have a ceiling of ULONG_MAX -1, which is effectively infinity on most platforms.

If you attempt an allocation that would cause a pool’s ceiling to be exceeded, the error MEM_CEILING_EXCEEDED results. SmartHeap then attempts to compact and shrink the pool. If this doesn’t free sufficient space to satisfy the allocation, then the allocation fails.

It is an error to set a pool’s ceiling lower than its floor or lower than its current size — calling MemPoolSetCeiling with such a value has no effect.

Comments You can use MemPoolSetCeiling to control your application’s resource usage. MemPoolSize will inform you of current memory resource consumption and is a starting point for determining a good value for ceiling.

Employing a ceiling can also be useful during debugging — exceeding a generous ceiling might point to problems in your application, such as leakage or an erroneously large size parameter to an allocation call.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also dbgMemReportLeakage, MemPoolSetFloor, MemPoolPreAllocate, MemPoolSetPageSize, MemPoolShrink, MemPoolSize, MemPoolWalk

Example #include <smrtheap.h>

/* establish a ceiling of 1 megabyte for
memory pool used by malloc and new, to
alert of excessive memory consumption
*/
int AlertCeiling(MEM_POOL pool)
{
MemPoolSetCeiling(MemDefaultPool,
1024 * 1024);
}

MemPoolSetFloor

Establishes the minimum size to which a memory pool can shrink.

Syntax #include <smrtheap.h>

unsigned long MemPoolSetFloor(MEM_POOL pool,
unsigned long floor);

Return value Returns the previous floor value of pool if successful, otherwise MEM_ERROR_RET.

Description MemPoolSetFloor establishes a threshold below which SmartHeap will not return free memory in pool to the operating system. The floor value behaves like a ratchet — if the pool size is currently less than floor, this function will not immediately increase the size of pool; however, the pool will grow and never shrink until its total size exceeds floor bytes.

The default value of floor is 256K. With this default setting, SmartHeap returns pages in a pool to the operating system when no blocks are in use on those pages only if the pool’s size exceeds 256K.

Note Prior to SmartHeap 3.1, the default floor value was zero, meaning SmartHeap formerly returned all pages in a pool to the operating system when no blocks are in use on those pages. The new behavior is an optimization to reduce the number of operating system calls.

It is an error to set a pool’s floor higher than its ceiling — calling MemPoolSetFloor with such a value has no effect.

Comments A pool’s size can temporarily drop below the floor value if you free an external block. An external block is one whose size exceeds approximately one quarter of the pool’s page size. SmartHeap normally sub-allocates blocks within fixed-size pages, for optimal locality of reference. However, when you request a very large allocation, SmartHeap allocates directly from the operating system. When SmartHeap frees this block, the memory is immediately returned to the operating system, regardless of the pool’s floor, since the memory region is not suitably sized for reuse as a page for subsequent sub-allocations.

MemPoolSetFloor is useful for avoiding system call overhead if a pool’s size is fluctuating widely. In this case, SmartHeap would repeatedly allocate and return pages to the operating system if no floor is established.

You can also use this function with MemPoolPreAllocate to reserve memory exclusively for one memory pool in advance of allocations from that pool. In multi-tasking environments, you should avoid reserving memory that you do not need right away — such resource hogging brings down overall system performance.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also MemPoolSetCeiling, MemPoolShrink, MemPoolSize

Example #include <smrtheap.h>

#define K(x) ((x) * 1024L)
struct Link {
int val;
struct Link *next;
};

/* reserve fixed-size memory for 1000 Link's,
plus 64K for variable-size blocks, then
set a floor to ensure that this memory is
not returned to the operating system
*/
int ReserveMem(MEM_POOL pool)
{
MemPoolPreAllocate(pool,
1000*sizeof(struct Link), MEM_FS_BLOCK);
MemPoolPreAllocate(pool,
K(64), MEM_VAR_FIXED_BLOCK);
MemPoolSetFloor(pool, MemPoolSize(pool));
}

MemPoolSetFreeBytes

Controls free space in a pool.

Syntax #include <smrtheap.h>

unsigned long MemPoolSetFreeBytes(MEM_POOL pool,
unsigned long bytes);

Return value Returns the previous value for free bytes in a pool.

Description MemPoolSetFreeBytes controls free space in a pool just as MemProcessSetFreeBytes controls free space in the large block heap. The default value is 1MB.

Note This API is available only in SmartHeap 6.0 or higher.

Comments Large values result in better performance and less contention at the expense of more heap space for allocations less than 16K in size. When this value is non-zero, SmartHeap leaves empty pages, up to the aggregate size specified, inside the pool. When a pool needs to add a page it can do so without a global lock or a large-block heap allocation by recycling a page previously freed by the same pool.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

See also MemProcessSetFreeBytes

Example #include <smrtheap.h>

main()
{
/* tell SmartHeap to leave free space, up
* to an aggregate value of 2M, inside
* the default pool
*/
MemPoolSetFreeBytes(MemDefaultPool,
2L * 1024L * 1024L);
}

MemPoolSetHighThreads

Establishes the contention versus space tradeoff for a memory pool.

Syntax #include <smrtheap.h>

void MemPoolSetHighThreads(MEM_POOL pool,
MEM_BOOL value);

Return value None.

Description MemPoolSetHighThreads determines whether SmartHeap will grow a memory pool, if necessary, in order to avoid contention in heavily threaded applications. If value is non-zero (the default), SmartHeap will avoid thread contention at the expense of memory space. With this setting, heavily threaded applications will potentially use more memory, but they will run faster because they will spend less time spin-locking, particularly on SMP systems.

Comments This API is useful only in multi-threaded applications, and it will have the greatest effect on SMP systems. It will have no effect in SmartHeap versions 6.02 and later.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

Example #include <smrtheap.h>

main()
{
/* tell SmartHeap that set space efficiency
* is more important than thread contention
* for the memory pool used by malloc and new
*/
MemPoolSetHighThreads(MemDefaultPool, FALSE);
}

MemPoolSetMaxSubpools

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

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolSetMaxSubpools(MEM_POOL pool,
unsigned count);

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

Description MemPoolSetMaxSubpools controls how many sub-pools SmartHeap will create in order to avoid heap contention. By default SmartHeap starts with a sub-pool count equal to processor count plus one. SmartHeap will then dynamically add sub-pools whenever threads contend for all the existing sub-pools, up to the limit specified by this API. The maximum value.

Note This API is available only in SmartHeap 6.0 or higher.

Comments This API is useful only in multi-threaded applications running on SMP systems. The only reason to call this API is if SmartHeap is consuming more memory space than desired in a very large, heavily threaded app on a multi-CPU system and some contention is acceptable in order to reduce the app’s footprint. Sub-pool count should not be reduced below processor count or significant heap contention will result.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

Example #include <smrtheap.h>

main()
{
/* tell SmartHeap that set space efficiency
* is more important than thread contention
* for the memory pool used by malloc and new
*/
MemPoolSetMaxSubpools(MemDefaultPool, 12);
}

MemPoolSetPageResizing

Controls whether SmartHeap resizes pages for increased space efficiency.

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolSetPageResizing(MEM_POOL pool,
MEM_BOOL);

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

Description SmartHeap 6 thru 7.2 resized pages for space efficiency, starting at thesystem page size up to 64 K in sys page increments. MemPoolSetPageResizing toggles this page resizing feature on or off. When it is off, all pages will be 64 K. Turning resizing off can improve performance for apps that have a very large number of small blocks of the same size.

Note This API is available only in SmartHeap 7.3 or higher.

Comments The second parameter to MemPoolSetPageResizing defaults to FALSE (resizing OFF) on Unix platforms, TRUE (resizing ON) on Microsoft Windows. Thus, Unix users may want to call this API with a second parameter of TRUE to improve space efficiency; Windows users may call it with FALSE to improve performance

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

Example #include <smrtheap.h>

main()
{
/* tell SmartHeap that speed is more important
* than space efficiency (platform is Windows)
*/
MemPoolSetPageResizing(MemDefaultPool, FALSE);
}

MemPoolSetPageSize

Establishes the page size for a memory pool.

Syntax #include <smrtheap.h>

unsigned MemPoolSetPageSize(MEM_POOL pool,
unsigned pageSize);

Return value Returns the previous page size of pool if successful, otherwise zero.

Description MemPoolSetPageSize establishes for pool the size of pages within which SmartHeap sub-allocates. SmartHeap rounds the pageSize parameter up to the next power of two that is a multiple of the system page size. pageSize may also be rounded down if it exceeds the maximum page size — a platform-dependent value that is 64K for many platforms.

The default page size is also platform dependent (see the Getting Started and Platform Guide) but generally varies between 4K and 16K bytes. You can use MemPoolInfo to determine a pool’s current page size.

You can change the page size of a pool at any time. Existing pages are unaffected by a change in page size, but subsequent pages that are added will have the new size.

The page size of a pool affects the maximum block size that SmartHeap can sub-allocate in that pool. SmartHeap allocates blocks larger than one quarter of the current page size directly from the operating system. Such external blocks are still owned by and managed with the pool, however, allocating external blocks is slower and wastes more memory due to coarser granularity. Therefore, for best performance, you should use a page size that is at least four times the size of blocks you frequently allocate.

It is an error to set a pool’s page size smaller than its fixed-size block size (see MemPoolSetBlockSizeFS).

Comments To establish the initial page size of the default memory pool (used by malloc and global operator new), use the global variable MemDefaultPoolPageSize.

MemPoolSetPageSize can be very useful for performance tuning, particularly in virtual memory operating systems. To minimize swapping or paging, set the page size equal to the system page size. SmartHeap pages contain no inter-page references for maximum locality. On the other hand, to maximize sub-allocation speed in physical memory, set the page size equal to about ten times the size of the largest blocks you will allocate. A good tradeoff for small blocks is generally a page size of 8K or 16K. For best performance, you should experiment with different page size values and measure actual application speed in each case.

In 16-bit protected-mode x86 versions of SmartHeap, each page in a memory pool consumes a selector. Because there is a system-wide limit of 8,192 selectors, you should set the page size no lower than the peak memory allocated by your app divided by 2,048 (for example, page size >= 8K if you allocate 16 MB).

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also MemDefaultPoolPageSize, MemPoolSize

Example #include <smrtheap.h>

/* set page size of malloc/new memory pool */
int SetMallocPageSize()
{
/* note: SmartHeap will round up to 16K */
MemPoolSetPageSize(MemDefaultPool, 16000);
}

MemPoolSetSerialization

Dynamically adjusts the serialization flag for a pool.

Note MemPoolSetSerializaton is a new API present only in SmartHeap 7 and higher.

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolSetSerialization(MEM_POOL pool, MEM_BOOL serialize);

Return value Returns the previous value for this facility.

Description Applications that are basically single-threaded, but occasionally or briefly multithreaded, can improve performance by turning on pool serialization only when required (because multiple threads may try to access the pool). This API gives you dynamic control of pool serialization. Obviously, it must be used with great caution: serialization can be turned off only when access to the pool is strictly from one thread at a time.

MemPoolSetSerialization can be called multiple times, toggling serialization on and off. The serialize parameter is non-zero to turn serialization on, or zero to turn serialization off. Note that this API functions on a specific pool. If used with the default pool, the pool parameter would be MemDefaultPool.

MemPoolSetSmallBlockAllocator

Establishes the small-block allocation algorithm for a given memory pool.

Note MemPoolSetSmallBlockAllocator is a new API present only in SmartHeap 5.0 and higher.

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolSetSmallBlockAllocator (MEM_POOL pool, MEM_SMALL_BLOCK_ALLOCATOR allocator);

Return value Non-zero if parameters are valid, otherwise zero.

Description MemPoolSetSmallBlockAllocator establishes or changes the algorithm SmartHeap uses to allocate small blocks allocated from pool by malloc, new, or MemAllocPtr. Small blocks are those smaller than the value established by MemPoolSetSmallBlockSize (default 256 bytes).

Specify one of the following values for allocator:

Flag Description

MEM_SMALL_BLOCK_NONE Disable the small-block allocator, and use the general-purpose variable-size allocator for all block sizes allocated from pool.

MEM_SMALL_BLOCK_SH3 Use the SmartHeap 3.0/4.0 small-block allocator, which has the following characteristics:

Flag Description

MEM_SMALL_BLOCK_SH5 Use the SmartHeap 5.0 small-block allocator, which has the following characteristics:

The default small-block allocator is MEM_SMALL_BLOCK_SH5 in SmartHeap 5.0.

Comments The SmartHeap 3.0/4.0 allocator (MEM_SMALL_BLOCK_SH3) is not available in SmartHeap for SMP.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

See also MemPoolSetSmallBlockSize

Example #include <smrtheap.h>


int main()

{

/* change malloc’s small-block allocator for

compatibility with SmartHeap 3.0 */

MemPoolSetSmallBlockAllocator(MemDefaultPool,

MEM_SMALL_BLOCK_SH3);

}

MemPoolSetSmallBlockSize

Establishes the small block size threshold for a memory pool.

Note MemPoolSetSmallBlockSize is present only in SmartHeap 3.1 and higher.

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolSetSmallBlockSize(MEM_POOL pool,
unsigned short blockSize);

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

Description Every memory pool has a block size threshold that determines which algorithm is used by the variable-size allocation APIs MemAllocPtr, MemReAlloc, malloc, calloc, realloc, and C++ operator new.

The MemPoolSetSmallBlockSize function establishes a pool’s small block size threshold. Blocks smaller than the threshold go to an extremely fast fixed-size allocator, while larger blocks go to the general-purpose variable-size allocator. Specify MemInitDefaultPool() for the pool parameter to change the small block threshold for malloc or operator new.

Memory pools have a default small block size threshold of 256 bytes. The maximum small block threshold is 1,000. You can change a memory pool’s small block threshold at any time.

If you don’t want the variable-size APIs to use the small-block allocator for small blocks, specify blockSize as zero. One reason you might want to disable the fixed-size allocator is if you have very few small blocks and you don’t want to waste a SmartHeap page for a few small blocks.

Comments You can use MemPoolSetSmallBlockSize to tune general-purpose allocations. In general, a larger blockSize causes allocations to be faster. However, when you free blocks allocated with the small-block algorithm, they are reserved for future allocations of the same size. Therefore, some applications will consume more memory if they specify a large small-block threshold.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_BLOCK_TOO_BIG blockSize is larger than 1K.

MEM_WRONG_TASK pool belongs to a different task.

See also MemPoolInfo, MemPoolInitFS, MemPoolSetPageSize, MemSizePtr

Example #include <smrtheap.h>

/* set small block size threshold to the size
* of the largest class or structure in the
* application that is commonly allocated
*/
int InitSmallBlockSize()
{
return MemPoolSetSmallBlockSize(
MemInitDefaultPool(), sizeof(Foobar));
}

MemPoolShrink

Returns unused memory in a pool to the operating system.

Syntax #include <smrtheap.h>

unsigned long MemPoolShrink(MEM_POOL pool);

Return value Returns the number of bytes of memory returned to the operating system (zero if no memory could be returned), or MEM_ERROR_RET if pool is invalid.

Description MemPoolShrink compacts all moveable pages, then frees all pages whose allocation count is zero. The function does not affect any memory blocks currently in use.

SmartHeap calls MemPoolShrink automatically if an allocation fails because there isn’t enough memory or because the ceiling established by MemPoolSetCeiling has been reached.

MemPoolShrink will never cause a pool to shrink below the floor established by MemPoolSetFloor.

Comments If you free memory from a particular pool and don’t expect to allocate the memory again in the near future, you might call MemPoolShrink to make the memory immediately available to other applications and/or to your other memory pools.

Windows 16-bit In the 16-bit Windows version of SmartHeap, you should also call MemPoolShrink for all of your memory pools when Windows sends the WM_COMPACTING message to top-level Windows. This is an indication that memory is extremely low.

SmartHeap also overrides _heapmin as a synonym for MemPoolShrink(MemDefaultPool) for compilers that define _heapmin.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also MemPoolFree, MemPoolSetFloor, MemPoolSetCeiling, MemPoolSize

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

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

/* 16-bit Windows example: window procedure
fragment that responds to WM_COMPACTING
message by calling MemPoolShrink */
long FAR PASCAL MainWndProc(HWND hWnd,
unsigned message, WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
/* ... */

case WM_COMPACTING:
MemPoolShrink(StringPool);
break;

/* ... */
}

return NULL;
}

MemPoolSize

Returns the total operating memory currently allocated by a memory pool.

Syntax #include <smrtheap.h>

unsigned long MemPoolSize(MEM_POOL pool);

Return value Returns the total number of bytes of operating system memory consumed by a memory pool or MEM_ERROR_RET if pool is invalid.

Description MemPoolSize gives you a quick indication of your application’s overall memory consumption. You might want to call MemPoolShrink if there is a large discrepancy between the total size of the memory pool and the sum of the sizes of allocated blocks currently in use.

MemPoolSize does not tell you how many bytes are in use in a memory pool — only the total operating system memory consumed. To determine how many bytes are free or in use in a pool, you could sum the in-use or free blocks by iterating over the pool with MemPoolWalk.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also MemPoolCount, MemPoolSetFloor, MemPoolSetCeiling, MemPoolShrink

Example #include <smrtheap.h>

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

#define AVERAGE_WORKING_SET_SIZE (24*1024)

/* DeleteLink removes the specified value
from a linked list, returning the new head.
See the MemFreeFS example for the
DeleteLink function definition. */
Link *DeleteLink(Link *head, int val);

/* delete many items from a linked list,
then shrink the memory pool to make
the memory available to others */
Link *DeleteMany(MEM_POOL pool, Link *head)
{
int i;

/* delete links with values
between 1 and 10,000 */
for (i = 1; i <= 10000; i++)
head = DeleteLink(head, i);

if (MemPoolSize(pool)
> AVERAGE_WORKING_SET_SIZE)
MemPoolShrink(pool);

return head;
}

MemPoolUnlock

Unlocks a memory pool that had exclusive access within current thread.

Syntax #include <smrtheap.h>

MEM_BOOL MemPoolUnlock(MEM_POOL pool);

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

Description MemPoolUnlock decrements the lock count of a given memory pool. When the lock-count is non-zero, the current thread has exclusive access to the memory pool until MemPoolUnlock reduces the lock count back to zero. When a thread has a pool locked, all SmartHeap calls from other threads that involve this memory pool, or memory blocks within this pool, are blocked.

Important! MemPoolLock has no effect unless the MEM_POOL_SERIALIZE flag was supplied at the time the memory pool was created.

Also important! Each call to MemPoolLock must be balanced with a later call to MemPoolUnlock to prevent operations on the pool from being blocked indefinitely in other threads.

Comments This function is useful in conjunction with MemPoolWalk, since MemPoolWalk requires exclusive access to its pool between calls. You can also use MemPoolLock if you want to prevent a thread from blocking due to heap serialization, for example, because it is a real-time thread.

Errors Error code Caused by

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also MemPoolUnlock, MemPoolWalk

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

/* Search all blocks in a memory pool for
the specified character string. */
char *SearchPool(MEM_POOL pool, char *str)
{
MEM_POOL_ENTRY entry;
unsigned len = strlen(str) + 1;
char *result = NULL;

entry.entry = NULL;

MemPoolLock(pool); /* lock pool while enumerating*/

while (MemPoolWalk(pool, &entry) == MEM_POOL_OK)
if (entry.isInUse && len <= entry.size
&& memcmp(entry.entry, str,len) == 0)
result = (char *)entry.entry;

MemPoolUnlock(pool);

return result;
}

MemPoolWalk

Traverses the entries of a memory pool.

Syntax #include <smrtheap.h>

MEM_POOL_STATUS MemPoolWalk(MEM_POOL pool,
MEM_POOL_ENTRY *poolEntry)

Return value Returns:

Description MemPoolWalk traverses each memory block in the pool, whether free or in use, reports any errors encountered, and returns information about each entry. Each call to MemPoolWalk traverses one entry in the pool. 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_BLOCK_TYPE;

Important! The first time you call MemPoolWalk, you must set the entry field of poolEntry to NULL; the function then obtains information about the first memory block. Each subsequent call to MemPoolWalk obtains data about subsequent blocks.

Caution! You must not allocate or free any blocks from pool between calls to MemPoolWalk (not even from a different thread). You can use MemPoolLock to prevent other threads from allocating or freeing from pool while you are using MemPoolWalk in the current thread.

Comments This function is intended for debugging, and should not be used for performance-critical tasks. Possible uses include diagnosing memory overwrites, searching a pool for a specific sequence of bytes, a memory browser utility, or a memory dumper.

Errors Error code Caused by

MEM_BAD_BLOCK Corrupt (overwritten) block detected.

MEM_BAD_FREE_BLOCK Corrupt free block detected.

MEM_BAD_MEM_POOL pool is invalid.

MEM_WRONG_TASK pool belongs to a different task.

See also MemCheckPtr, MemPoolCheck, MemPoolCount, MemPoolSize, dbgMemReportLeakage

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

/* Search all blocks in a memory pool for
the specified character string. */
char *SearchPool(MEM_POOL pool, char *str)
{
MEM_POOL_ENTRY entry;
unsigned len = strlen(str) + 1;
char *result = NULL;

entry.entry = NULL;

MemPoolLock(pool); /* lock pool while enumerating*/

while (MemPoolWalk(pool, &entry) == MEM_POOL_OK)
if (entry.isInUse && len <= entry.size
&& memcmp(entry.entry, str,len) == 0)
result = (char *)entry.entry;

MemPoolUnlock(pool);

return result;
}

MemProcessCoelesceSystemAllocs

Disable coelescing of operating system allocations, which prevents SmartHeap from creating an allocation that spans operating system blocks. As far as we are aware, this is only an issue with the Microsoft Windows GDI.

Note MemProcessCoelesceSystemAllocs is a new API present only in SmartHeap 6.03 and higher.

Syntax #include <smrtheap.h>

MEM_BOOL MemProcessCoelesceSystemAllocs(MEM_BOOL bool);

Return value Returns the previous setting for this facility.

Description On Windows, SmartHeap calls VirtualAlloc to obtain the large blocks of memory that it manages for the process. When SmartHeap returns a pointer to a large block of memory, the alloc may begin in one VirtualAlloc’ed block of memory and continue past the end of the block and into the adjacent VirtualAlloc’ed block. Some Windows subsystems (the only one we’re aware of is the Microsoft GDI) attempt to setup a Virtual Address Descriptor or VAD that maps the input pointer to the DIB function so that it can be accessed by the kernel parts of GDI. This imposes a requirement that the pointer cannot span across VirtualAlloc boundaries. In the cases where it does, the DIB function fails to operate correctly and returns an error.

Passing a non-zero parameter to MemProcessCoelesceSystemAllocs tells SmartHeap to avoid creating allocations that span VirtualAlloc blocks.

MemProcessFlushAll

On Win32, this call releases all the memory used internally by the SmartHeap large block heap and reinitializes the large block heap to startup state.

Note MemProcessFlushAll is a new API present only in SmartHeap 7 and higher.

Syntax #include <smrtheap.h>

void MemProcessFlushAll(void);

Return value None.

Description This API should never be called except after freeing all memory pools, including the default pool. The only time it is useful is when freeing a dynamically loaded DLL that statically links to SmartHeap. Even in that case, if the application has been linked to SmartHeap via the “Quick Start” linking procedure (see the Windows Getting Started Guide), this API is not needed.

MemProcessSetFreeBytes

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

Syntax #include <smrtheap.h>

void MemProcessSetFreeBytes(unsigned long bytes);

Return value None.

Description MemProcessSetFreeBytes enables the user to control exactly when SmartHeap returns memory to the OS.

Note This API is available only in SmartHeap 6.0 or higher.

Comments In SmartHeap 5 this value was infinite (memory was never returned to the OS). In SmartHeap 6 the default value is 10MB, meaning that SmartHeap won’t start releasing memory to the OS until the large block heap has more than 10MB of free space. Larger values result in better allocation performance but potentially larger process footprint.

See also MemPoolSetFreeBytes

Example #include <smrtheap.h>

main()
{
/* increase the max amount of free
* space SmartHeap will keep in the
* large block heap to 200M
*/
MemProcessSetFreeBytes(200L * 1024L * 1024L);
}

MemProcessSetGrowIncrement

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

Note MemProcessSetGrowIncrement is a new API present only in SmartHeap 5.0 and higher.

Syntax #include <smrtheap.h>

void MemProcessSetGrowIncrement(unsigned long bytes);

Return value None.

Description The MemProcessSetGrowIncrement function determines the minimum size of allocation requests SmartHeap makes of the operating system. When SmartHeap requests memory from the operating system, it stores the memory in an “external” heap for use by any memory pool that subsequently grows.

By buffering operating system heap requests, SmartHeap 5.0 incurs less system call overhead, less operating system heap and address space fragmentation, and less operating system heap contention.

The default process grow increment is 2MB. The value you specify to MemProcessSetGrowIncrement is in bytes and is rounded up to the next 64K.

See also MemPoolSetFloor, MemPoolPreAllocate

Example #include <smrtheap.h>


int main()

{

/* set process grow increment to 16MB */

MemProcessSetGrowIncrement(16L * 1024L * 1024L);

}

MemProcessSetHeapLimit

Sets an upper limit on the overall process heap footprint.

Note MemProcessSetHeapLimit is a new API present only in SmartHeap 6.03 and higher.

Syntax #include <smrtheap.h>

ulong MemProcessSetHeapLimit(unsigned long bytes);

Return value None.

Description Note that this is only the process heap that SmartHeap requests. You will have to determine empirically the other memory the process allocates for code, static data, stack, and so on to achieve the target process limit. If the process limit is exceeded, SmartHeap will report the MEM_EXCEEDED_PROCESS_LIMIT error, and also MEM_OUT_OF_MEMORY which is reported at higher levels in SmartHeap. Note that no error reporting will take place by default in SmartHeap/SMP, but these error reports could be used for informational purposes if desired by defining a custom error handler. The parameter is a value in bytes which is the maximum aggregate size that SH will allocate from the OS, except to handle SH-internal data structures if SH tries to allocate one of these small items when the process heap limit is exceeded.

MemProcessSetLargeBlockThreshold

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

Syntax #include <smrtheap.h>

void MemProcessSetLargeBlockThreshold
(unsigned long bytes);

Return value None.

Description MemProcessSetLargeBlockThreshold controls the block size SmartHeap manages in its large block heap. Blocks larger than the threshold value are allocated by the OS and freed directly to the OS.

Note This API is available only in SmartHeap 6.0 or higher.

Comments The default size is 512KB. Larger values result in better performance but potentially larger process footprint.

See also MemProcessSetFreeBytes

Example #include <smrtheap.h>

main()
{
/* raise the threshold to
* 1M
*/
MemProcessSetLargeBlockThreshold(1024L * 1024L);
}

MemProcessUseMunmap

Enable using munmap to return memory to the OS for UNIX platforms that support this (Solaris, OSF, and SGI).

Note MemProcessUseMunmap is a new API present only in SmartHeap 6.02 and higher.

Syntax #include <smrtheap.h>

MEM_BOOL MemProcessUseMunmap(MEM_BOOL bool);

Return value Returns the previous setting for this facility.

Description As originally conceived and implemented in SmartHeap 6.02, calling MemProcessUseMunmap(<non-zero>) caused SmartHeap to aggressively use munmap to return memory to the OS even if it was allocated with sbrk. However, there was a bug in this implementation. When it was fixed, in December 2002, the implementation was changed. SmartHeap now uses madvise to commit/decommit memory. The address space occupied by free regions is thus never released, but the unused memory is. MemProcessUseMunmap is still defined, but it now (since December 2002) affects only the release of this address space. madvise is used to return memory regardless of the MemProcessUseMunmap setting.

A non-zero parameter will enable this facility. Note that once enabled, this facility cannot be turned off for the life of the process.

MemReAlloc

Changes the size of a handle-based memory block.

Syntax #include <smrtheap.h>

MEM_HANDLE MemReAlloc(MEM_HANDLE hMem,
unsigned long size, unsigned flags);

Return value Returns hMem if successful, or returns NULL if there is insufficient memory, if hMem is invalid, or if size is zero.

Description The MemReAlloc function changes the size of a block to size bytes. The hMem parameter must be a handle previously returned by MemAlloc. size may be smaller or larger than the original size; the block is shrunk or expanded accordingly.

If the memory block is growing, the additional memory contents are uninitialized unless flags specifies MEM_ZEROINIT. To construct the flags parameter, bitwise OR one or more of the following values:

MEM_MOVEABLE

If the block specified by hMem is fixed, this flag lets the reallocated block be moved to a new fixed location. Do not use with MEM_RESIZE_IN_PLACE.

MEM_NOCOMPACT

Does not compact memory to satisfy the allocation request. Use for allocations that need to be as fast as possible.

MEM_NOEXTERNAL

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

MEM_RESIZEABLE

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

MEM_RESIZE_IN_PLACE

Memory does not move — function fails if it can’t resize in place.

MEM_ZEROINIT

If the block is growing, initializes additional memory contents to zero. Use only if MEM_ZEROINIT was specified both for the original allocation and for all previous reallocations, and if all previous reallocs expanded the block.

The size of the allocated block will be at least size bytes, possibly larger. Use MemSize to determine the exact size.

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 such huge blocks is not zero. As a result, 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 the offset is zero.

Errors Error code Caused by

MEM_ALLOC_ZERO size is zero.

MEM_BAD_FLAGS Invalid flags parameter.

MEM_BAD_HANDLE hMem is invalid.

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

MEM_OUT_OF_MEMORY There is insufficient memory.

MEM_NOREALLOC hMem was marked as “no realloc” by dbgMemProtectPtr.

MEM_RESIZE_FAILED hMem is a fixed block, flags does not specify MEM_MOVEABLE, or flags specifies MEM_RESIZE_IN_PLACE, but the block can’t grow in place.

MEM_WRONG_TASK hMem was allocated in a different task.

See also MemAlloc, MemReAllocPtr, MemSize, realloc

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

/* add an entry to a string table */
int AddEntry(MEM_HANDLE hStrTable, char *val)
{
int i;
char **pStrTable =
(char **)MEM_REFERENCE(hStrTable);

/* find vacant entry in table */
for (;;)
{
/* search for an empty entry */
for (i = 0; i < StrTableSize; i++)
if (pStrTable[i] == NULL) {
/* found vacant entry: update */
pStrTable[i] = val;
return TRUE;
}

/* all entries in use: expand table */
if (MemReAlloc(hStrTable,
sizeof(char *) * StrTableSize*2,
MEM_ZEROINIT | MEM_MOVEABLE)) {
StrTableSize *= 2;
/* must dereference handle again,
as block may have moved */
pStrTable =
(char **)MEM_REFERENCE(hStrTable);
}
else
return FALSE;
}
}

MemReAllocPtr

Changes the size of a memory block.

Syntax #include <smrtheap.h>

void *MemReAllocPtr(void *mem, 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 mem is invalid, or if size is zero.

Description The MemReAllocPtr function changes, to size bytes, the size of the block that mem points to. The mem parameter must be a pointer to a memory block previously allocated by calloc, malloc, realloc, MemAllocPtr, MemReAllocPtr, MemAllocFS, or C++ operator new. size may be smaller or larger than the original size; the block is shrunk or expanded, respectively.

If the memory block is growing, the additional memory contents are uninitialized unless flags specifies MEM_ZEROINIT. 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_RESIZEABLE

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

MEM_RESIZE_IN_PLACE

Memory does not move — function fails if it can’t resize in place.

MEM_ZEROINIT

If the block is growing, initializes additional memory contents to zero. Use only if MEM_ZEROINIT was specified both for the original allocation and for all previous reallocations, and if all previous reallocs expanded the block.

The size of the allocated block will be at least size bytes. Use MemSizePtr to determine the exact size.

Comments For 16-bit x86 platforms, a huge block is returned if size exceeds approximately 65510 — see MemReAlloc for details.

If flags does not specify MEM_RESIZE_IN_PLACE, the memory block may be moved to satisfy the allocation request, that is, mem might not be the same as the function’s result. If the function succeeds and the block is moved, mem is freed. If the function fails, mem isn’t freed and, therefore, remains a valid pointer.

Errors Error code Caused by

MEM_ALLOC_ZERO size is zero.

MEM_BAD_FLAGS Invalid flags parameter.

MEM_BAD_POINTER mem is invalid.

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

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

MEM_NOREALLOC mem was marked as “no realloc” by dbgMemProtectPtr.

MEM_RESIZE_FAILED flags specifies MEM_RESIZE_IN_PLACE, and the block can’t be expanded in place.

MEM_WRONG_TASK mem was allocated in a different task.

See also MemReAlloc, MemSizePtr, realloc

Example #include <smrtheap.h>

/* add an entry to a string table,
return pointer to updated table
*/
char **AddEntry(char **pStrTable, char *val)
{
int i;

/* find a vacant entry in string table */
for (;;)
{
/* search for an empty entry */
for (i = 0; i < StrTableSize; i++)
if (pStrTable[i] == NULL)
{
/* found a vacant entry: update */
pStrTable[i] = val;
return pStrTable;
}

/* all entries in use: expand table */
pStrTable = (char **)
MemReAllocPtr(pStrTable,
sizeof(char *) * StrTableSize*2,
MEM_ZEROINIT);

if (pStrTable)
StrTableSize *= 2;
else
return NULL;
}
}

MEM_REFERENCE

Macro for temporarily dereferencing a memory handle allocated by MemAlloc.

Syntax #include <smrtheap.h>

void *MEM_REFERENCE(MEM_HANDLE hMem);

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

Description MEM_REFERENCE is used to temporarily, but very efficiently, access the address of a block identified by memory handle hMem. The block need not be locked. MEM_REFERENCE works on all handle-based blocks — fixed or moveable.

In the Runtime version of SmartHeap, MEM_REFERENCE is implemented as a simple indirection, as on the Mac. In the debugging version of SmartHeap, MEM_REFERENCE is a function that validates the handle before dereferencing.

Caution! Do not retain a pointer obtained from MEM_REFERENCE across any calls to SmartHeap unless hMem is known to be locked. The address can change if the heap is compacted, which can occur on numerous SmartHeap calls. Similarly, avoid MEM_REFERENCE if the memory pool containing hMem is used in more than one thread of a multi-threaded application (MEM_REFERENCE, being a simple pointer dereference, is never thread-synchronized).

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. Use MemFix to retain a reference to a block for an extended period.

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;
}

/* update contents of moveable block without
locking; compare to the MemLock example */
int SetString(int index, char *value)
{
/* obtain address of table -- no need to lock
the handle because we do not retain
a reference across calls to SmartHeap */
char **pStringTable =
(char **)MEM_REFERENCE(hStringTable);
if (!pStringTable)
return FALSE;

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

/* no need to unlock -- we haven't locked */
return TRUE;
}

MemRegisterTask

Registers the current task or process for use with the SmartHeap library.

Syntax #include <smrtheap.h>

MEM_BOOL MemRegisterTask(void);

Return value The return value is non-zero if successful, or zero if registration fails (fails only in extreme low-memory conditions).

Description MemRegisterTask increases the registration reference count of the current process. You generally do not need to explicitly call MemRegisterTask. Except as noted below, SmartHeap calls that require registration register implicitly.

Important! If you’re using a version of SmartHeap that supports multi-threading, you must call MemRegisterTask from the first thread before secondary threads call SmartHeap. This ensures that SmartHeap can initialize synchronization objects before they’re used.

MemUnregisterTask decreases the registration reference count by one. When the reference count is reduced to zero, all memory pools, error handlers, and the SmartHeap debugging state in the current process are freed.

Windows 16-bit In the 16-bit Windows version of SmartHeap, when you call MemRegisterTask from a DLL, the DLL (not the current task) is registered with SmartHeap. Each Windows DLL can therefore maintain its own SmartHeap error handler and debugging state. Note that this represents different semantics from previous SmartHeap releases, where MemRegisterTask always registered the current task. It is an error to have a DLL call MemRegisterTask on behalf of an EXE. The function that calls MemRegisterTask must be directly linked with the Windows module that is to be registered.

In the 16-bit Windows DLL, the first call to MemRegisterTask initializes a background EXE that monitors Windows task and module termination. This monitor EXE remains loaded until all clients of the SmartHeap DLL terminate. To ensure proper termination of SmartHeap clients, each application should call MemRegisterTask before any of its modules that use SmartHeap terminate. Note that, because MemRegisterTask potentially starts a new task, the call may cause a context switch. Therefore, place calls to MemRegisterTask where relinquishing control to other Windows tasks is acceptable. MemRegisterTask isn’t required if you statically link SmartHeap.

Errors Error code Caused by

MEM_OUT_OF_MEMORY Memory is extremely low.

MEM_TOO_MANY_TASKS Attempted to register too many tasks — occurs only in 16-bit Windows version, where the limit is several hundred tasks.

See also MemUnregisterTask

Example #include <smrtheap.h>

/* Example main, showing SmartHeap
registration and un-registration. */
int main()
{
/* register with SmartHeap */
MemRegisterTask();

/* ... application code ... */

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

MemSetErrorHandler

Establishes an error-handling routine to handle SmartHeap errors.

Syntax #include <smrtheap.h>

MEM_ERROR_FN MemSetErrorHandler(
MEM_ERROR_FN errorFn);

Return value Returns the error-handling routine that was in effect for the current task prior to this call if successful, otherwise NULL.

Description MemSetErrorHandler lets you provide your own error handler for memory errors in your application. If you do not call MemSetErrorHandler, all memory errors are handled by MemDefaultErrorHandler. If you do not want errors to be handled at all, supply the value NULL for errorFn. In this case, all SmartHeap APIs will silently return error return values on failure.

errorFn has the following prototype:

MEM_BOOL MEM_CALLBACK ErrorFn(MEM_ERROR_INFO *errorInfo);

Replace ErrorFn, above, with your function name.

Important! ErrorFn must have the correct calling convention. MEM_CALLBACK is defined in smrtheap.h as the appropriate calling convention for the SmartHeap error handler, provided that you define the macro symbol for your platform that smrtheap.h recognizes. For all 16-bit x86 platforms, use the far pascal calling convention. For 16-bit x86 DLL versions of SmartHeap, you must use _loadds to cause DS to be set to DGROUP on entry to ErrorFn.

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

MEM_ERROR_INFO is declared in smrtheap.h as follows:

typedef struct {
MEM_ERROR_CODE errorCode;
type of error
MEM_POOL pool;
pool where error occurred

All fields below this are NULL in non-debug version of SmartHeap.

The following 8 fields identify the call that detected the error:
MEM_API errorAPI;
API where error detected
MEM_POOL argPool; pool parameter, if any
void *argPtr;
pointer parameter, if any
void *argBuf;
buffer parameter, if any
MEM_HANDLE argHandle;
handle parameter, if any
unsigned long argSize;
size parameter, if any
unsigned long argCount;
count parameter, if any
unsigned argFlags;
flags parameter, if any

The following 2 fields identify source file/line of error detection:
const char *file;
source file name
int line;
line number in above file

The following 3 fields identify call instance of error detection:
unsigned long allocCount;
enumeration of alloc
unsigned long passCount;
pass # at above file/line
unsigned checkpoint;
context or group of alloc

The following 2 fields, if non-NULL, point to the address where
a corruption was detected and to another MEM_ERROR_INFO
structure identifying where the corrupted object was created:

void *corruptAddr;
MEM_ERROR_INFO *objectCreationInfo;
unsigned long threadID;
unsigned long pid;
} MEM_ERROR_INFO;

The errorCode field identifies the type of error that has occurred. See §4.3, “Error codes,” for possible values, and the meanings and causes of each type of error.

In the Debug version of SmartHeap, the remaining fields of MEM_ERROR_INFO provide detailed information on when and where the error was detected, including the API that detected the error (with a full parameter list), the address of a corruption, if any, and the API, parameters, and location of the call that originally created the now-corrupted object. The thread and process where the error was detected are also identified on multi-threaded and shared memory platforms, respectively.

The errorAPI field of type MEM_API identifies the SmartHeap entry-point API where the error was detected, or, for objectCreationInfo, where the object involved in the error was created. MEM_API is declared in smrtheap.h. The values are SmartHeap API names in uppercase, prefixed with “MEM_”, for example, MEM_MEMALLOCPTR for MemAllocPtr. The ANSI C APIs are prefixed with “MEM_MEM_” — for example, MEM_MEM_MALLOC for malloc.

You can use dbgMemFormatErrorInfo and/or dbgMemFormatCall to construct an error message from this information (as MemDefaultErrorHandler does).Alternatively, you can programmatically analyze the information from your error handler.

The result of ErrorFn is ignored for all error types except the following:

Error type Return value Meaning

MEM_OUT_OF_MEMORY Non-zero Retry the allocation.
Zero Allocation fails.

MEM_LEAKAGE Non-zero Continue leakage report.
Zero End leakage report.

MEM_WRONG_TASK Zero Stop reporting wrong-task
(16-bit Windows only) references as errors

Caution! If errorCode is MEM_OUT_OF_MEMORY, you should avoid calling any function that might try to allocate dynamic memory (including C runtime functions such as sprintf or fopen that call malloc), to avoid recursively nested error reports.

You can establish error handlers that are specific to one or more memory pools by chaining error handlers. You do this by calling the previous error handler (the return value of MemSetErrorHandler) if the pool doesn’t belong to you. Chaining error handlers in this way is a good practice if there is a possibility that other modules or libraries are also using SmartHeap. This avoids clobbering someone else’s error handler if an error occurs in their memory pool.

Important! If your error handler does not return to SmartHeap (for example, because it non-local exits with longjmp, as described above), it must call MemErrorUnwind immediately before the non-local exit. This informs SmartHeap that the error handler won’t return. Failure to call MemErrorUnwind will result in erroneous reports of recursive error-handler re-entry.

Comments You can avoid the need for memory related error handling throughout your code. Just store the execution environment at top-level in your program with setjmp or (Catch for Windows), and invoke longjmp (Throw) from your error handler. That is, if your error handler induces a non-local exit on error conditions, you don’t need to check the return values of the SmartHeap functions and handle error return values. For example, if your error handler ensures that failing allocations never return to the caller, your code can assume that all allocations succeed.

Windows 16-bit For 16-bit Windows, MemSetErrorHandler 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). You must therefore call MemSetErrorHandler once from each DLL and each EXE instance that calls SmartHeap. If multiple tasks and/or DLLs are using the SmartHeap DLL, SmartHeap will report errors to the error handler established by the EXE instance or DLL that called the SmartHeap function that detected the error This is not necessarily the error handler of the current task or of the task that owns the erroneous object.

See also MemDefaultErrorHandler, dbgMemFormatCall, dbgMemFormatErrorInfo, dbgMemSetEntryHandler, dbgMemSetExitHandle

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

MEM_POOL StringPool;
MEM_ERROR_FN PrevErrorHandler;
jmp_buf jbuf;

MEM_BOOL MEM_CALLBACK MyErrorHandler(MEM_ERROR_INFO *);

/* Example main: initialize memory pool,
establish error handler, and set up
jmp buffer for error-handler. */
int main()
{
/* register with SmartHeap */
MemRegisterTask();

/* initialize pool */
StringPool = MemPoolInit(MEM_POOL_DEFAULT);

/* establish error handler */
PrevErrorHandler =
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();
return 0;
}

/* Error-handler definition */
MEM_BOOL MEM_CALLBACK MyErrorHandler(
MEM_ERROR_INFO *errorInfo)
{
/* chain if this is not our error */
if (errorInfo->pool != StringPool) {
if (PrevErrorHandler)
return (*PrevErrorHandler)(errorInfo);
else
return FALSE;
}

/* if out of memory, tell SmartHeap to retry
(indicated by a non-zero return value
from error handler) */
if (errorInfo->errorCode ==
MEM_OUT_OF_MEMORY) {
if (MessageBox(NULL,
"Out of Memory. Close some windows.",
NULL, MB_RETRYCANCEL)
== IDRETRY)
return TRUE;
}
#ifdef MEM_DEBUG
else {
/* print error message in debug build */
char buf[801];
dbgMemFormatErrorInfo(errorInfo,buf,800);
OutputDebugString(buf);
}
#endif

/* inform SmartHeap about non-local exit */
MemErrorUnwind();
/* and throw back to top-level (cancel) */
longjmp(jbuf, 1);
}

MemSize

Returns the size of a memory block allocated with MemAlloc.

Syntax #include <smrtheap.h>

unsigned long MemSize(MEM_HANDLE hMem);

Return value The return value is the size in bytes of the memory block associated with hMem, or MEM_ERROR_RET if hMem is invalid.

Description Due to alignment, the actual size of a block allocated by MemAlloc may be greater than the size you requested. Use MemSizeRequested to determine the requested size of the block.

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, MemPoolSize, MemPoolWalk, MemReAlloc, MemSizePtr, MemSizeRequested

Example #include <smrtheap.h>

typedef struct
{
unsigned long size;
char contents[1];
} VarArray;

/* allocate a variable-sized array,
storing the actual allocated size */
MEM_HANDLE MakeArray(MEM_POOL pool,
unsigned long size)
{
VarArray *result;
MEM_HANDLE hResult =
MemAlloc(pool, MEM_MOVEABLE,
sizeof(VarArray) + size - 1);

if (!hResult)
return NULL;

result = (VarArray *)MEM_REFERENCE(hResult);
if (!result)
{
MemFree(hResult);
return NULL;
}

/* Record total available size, which
may be more than we asked for, so
that every byte can be utilized. */
result->size =
MemSize(hResult) - sizeof(VarArray) + 1;

return hResult;
}

MemSizeRequested

Returns the requested size of a memory block allocated with MemAlloc.

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

Syntax #include <smrtheap.h>

unsigned long MemSizeRequested(MEM_HANDLE hMem);

Return value The return value is the requested size in bytes of the memory block associated with hMem, or MEM_ERROR_RET if hMem is invalid.

Description Due to alignment, the actual size of a block allocated by MemAlloc may be greater than the size you requested. Use MemSize to determine the actual size of the block.

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, MemPoolSize, MemPoolWalk, MemReAlloc, MemSize, MemSizePtr

Example #include <smrtheap.h>

#define nilHandleErr ((MEM_HANDLE)-1)
#define nmemFullErr ((MEM_HANDLE)-2)

/* implementation of the Mac PtrAndHand routine,
* which appends data that is pointed to by ptr
* to the end of the data that is indirectly
* pointed to by hand
*/
int PtrAndHand(const void *ptr, MEM_HANDLE hand,
long size1)
{
unsigned long size2;

if (!hand)
return nilHandleErr;

size2 = MemSizeRequested(hand);

if (!MemReAlloc(hand, size1+size2, MEM_NOCOMPACT))
return memFullErr;

memcpy((char *)MEM_REFERENCE(hand) + size2, ptr,
size1);

return 0;
}

MemSizePtr

Returns the size of a memory block.

Syntax #include <smrtheap.h>

unsigned long MemSizePtr(void *mem);

Return value The return value is the size in bytes of the memory block pointed to by mem, or MEM_ERROR_RET if mem is invalid.

Description Due to alignment, the actual size of an allocation may be greater than the size you requested. MemSizePtr determines the actual size of the memory block pointed to by mem. The block must have been previously allocated by SmartHeap calloc, malloc, realloc, ::operator new, MemAllocPtr, MemReAllocPtr, or MemAllocFS.

Comments SmartHeap also overrides _msize and _fmsize for compilers that define these functions.

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 malloc, MemAllocPtr, MemPoolSize, MemReAllocPtr, MemSize, realloc

Example #include <smrtheap.h>

typedef struct
{
unsigned long size;
char contents[1];
} VarArray;

/* allocate a variable-sized array,
filling in the actual allocated size */
VarArray *MakeArray(MEM_POOL pool,
unsigned long size)
{
VarArray *result = MemAllocPtr(pool,
sizeof(VarArray) + size - 1, 0);

if (!result)
return NULL;

/* Record total available size, which
may be more than we asked for, so
that every byte can be utilized. */
result->size =
MemSizePtr(result) - sizeof(VarArray) + 1;

return result;
}

MemUnfix

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

Syntax #include <smrtheap.h>

unsigned MemUnfix(MEM_HANDLE hMem);

Return value Returns the new value of hMem’s reference count if successful, otherwise MEM_UNLOCK_FAILED.

Description MemUnfix is used to release the lock on a fixed handle-based memory block previously fixed by MemFix. The block’s reference count is reduced by one. If the reference count becomes zero, SmartHeap moves the block from the fixed to the moveable heap, where it is subject to movement when the heap is compacted.

It is an error to call MemUnfix on a block that is currently on the moveable heap. Use MemUnlock to unlock moveable blocks. Use MemIsMoveable to determine whether a block is currently on the fixed heap or on the moveable heap.

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 already a moveable block.

MEM_WRONG_TASK hMem allocated in a different task.

See also MemAlloc, MemFix, MemHandle, MemIsMoveable, MemLock, 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; there are
memory allocation calls between
references, so the pool's moveable
heap may be compacted ... */

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

MemUnlock

Unlocks a moveable block allocated by MemAlloc and locked by MemLock.

Syntax #include <smrtheap.h>

unsigned MemUnlock(MEM_HANDLE hMem);

Return value Returns the new value of hMem’s lock count if successful, otherwise MEM_UNLOCK_FAILED.

Description MemUnlock decreases the block’s lock count by one. When the lock count is reduced to zero, the memory block is subject to moving when SmartHeap compacts the heap.

It is an error to call MemUnlock on a fixed-handle-based block. Use MemUnfix for such blocks. Use MemIsMoveable to determine whether a block is currently on the fixed heap or on 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_LOCK_ERROR hMem is a fixed block, or the lock count is already zero.

MEM_WRONG_TASK hMem was allocated in a different task.

See also MemAlloc, MemFix, MemUnfix, MemIsMoveable, MemLock

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(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;
}

MemUnregisterTask

Unregisters the current task from the SmartHeap library.

Syntax #include <smrtheap.h>

MEM_BOOL MemUnregisterTask(void);

Return value The return value is non-zero if the current task was registered, or zero if it was not registered with SmartHeap.

Description MemUnregisterTask decreases the registration reference count of the current task or process by one. If the reference count is reduced to zero, all memory pools, error handlers, and the debugging state in the current task are freed.

You should not call MemUnregisterTask unless you previously made a corresponding call to MemRegisterTask.

Windows 16-bit In 16-bit Windows, MemUnregisterTask unregisters from the current task, if called from an EXE, or from the module of a DLL, if called from a DLL. It is an error to have a DLL call MemUnregisterTask on behalf of an EXE. The function that calls MemUnregisterTask must be directly linked with the Windows module that is to be unregistered.

See also MemRegisterTask, MemPoolFree

Example #include <smrtheap.h>

/* Example main, showing SmartHeap
registration and un-registration. */
int main()
{
/* register with SmartHeap */
MemRegisterTask();

/* ... application code ... */

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

MemVersion

Returns the version of the SmartHeap library.

Syntax #include <smrtheap.h>

MEM_VERSION MemVersion(void);

Return value Returns an integral value that represents the major, minor, and update versions of SmartHeap.

Description MemVersion returns a number representing the major, minor, and update versions of the SmartHeap library. The following macros allow you to extract these component versions:

MEM_MAJOR_VERSION(ver)

MEM_MINOR_VERSION(ver)

MEM_UPDATE_VERSION(ver)

Important! If you distribute a dynamic-link library (DLL) version of SmartHeap with your application, it is important that you check for existing versions of the SmartHeap DLL on the target machine to prevent overwriting a newer version with an older version. The example below illustrates how to use MemVersion for this purpose.

Comments Windows 16-bit With the 16-bit Windows DLL version of SmartHeap, you can also use the VER.DLL facility provided with MS Windows 3.1 and higher — the SmartHeap DLL contains the appropriate version resources. See your Windows SDK documentation for details on using VER.DLL.

Example #include <smrtheap.h>

#include <windows.h> // Windows only

typedef MEM_VERSION (FAR PASCAL _export
*MEM_VERSION_FN)(void);

BOOL IsSmartHeapNewer(LPSTR szExistingPath,
LPSTR szInstallPath)
{
MEM_VERSION_FN lpVersionProc;
MEM_VERSION existingVersion, installVersion;
HANDLE hDLL;
BOOL bDoInstall;

if ((hDLL=LoadLibrary(szExistingPath)) < 32)
// no existing version: install ours
return TRUE;

if ((lpVersionProc = (MEM_VERSION_FN)
GetProcAddress(hDLL,"MemVersion"))!= NULL)
{
existingVersion = (*lpVersionProc)();
FreeLibrary(hDLL);
if ((hDLL=LoadLibrary(szInstallPath))>=32)
{
if ((lpVersionProc = (MEM_VERSION_FN)
GetProcAddress(hDLL, "MemVersion"))
!= NULL)
installVersion = (*lpVersionProc)();
FreeLibrary(hDLL);

// both versions have MemVersion API:
// install our version if it is newer
bDoInstall =
(installVersion > existingVersion);
}
else
// error loading our version
bDoInstall = FALSE;
}
else {
// if existing version doesn't have
// MemVersion API, it must be older
bDoInstall = TRUE;
FreeLibrary(hDLL);
}
return bDoInstall;
}

new

C++ memory allocation operator.

Syntax operator new declaration syntax:

void far *operator new(size_t sz);

or

void far *operator new(size_t sz, MEM_POOL pool,
unsigned flags=0);

operator new usage syntax:

#include <smrtheap.hpp>
pointer-to-type = new type-name;

or

pointer-to-type = new (pool [, flags]) type-name;

Return value Returns a far pointer of type type-name to the allocated space. The return value is NULL if there is insufficient memory.

Description The new operator allocates a block to hold one object of type type-name. This may be any valid C++ type except “function returning...” (however, pointers to functions are permitted).

The first form of operator new is the standard global ::operator new(). This allocates from the default C++ memory pool, MemDefaultPool.

In the second form of operator new, you specify a memory pool and optional initializer using the placement syntax of C++. The allocation occurs from a memory pool you previously allocated with MemPoolInit or MemPoolInitFS. The memory is uninitialized by default, or initialized to all zeros if flags includes MEM_ZEROINIT (see MemAllocPtr for valid flags values).

If you have (or want) a C++ new_handler, you can define a SmartHeap error handler and have it call new_handler.

Comments If you have dynamic data structures represented by C++ class objects, it is often a good idea to define your own operator new for each class, as shown in the example below. To improve memory utilization and performance for cases where you will create many class objects, use a fixed-size memory pool. If you use this technique, you’ll have to define an operator new for derived classes with additional data members, since objects of such derived classes do not have the same size as objects of the base class.

In 16-bit x86 versions of SmartHeap, ::operator new is a far function returning a far pointer regardless of memory model. Therefore, it requires the large memory model. SmartHeap also overrides far and huge forms of ::operator new for compilers that define these.

Errors Error code Caused by

MEM_EXCEEDED_CEILING Total allocations in pool exceed size set by MemPoolSetCeiling.

MEM_OUT_OF_MEMORY There is insufficient memory to satisfy the allocation request.

See also delete, malloc, MemAllocFS, MemAllocPtr

Example #include <smrtheap.hpp>

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

// overload operators new and delete to
// allocate Link's from fixed-size pool
void *operator new(size_t size) {
if (size == sizeof(Link)
return MemAllocFS(pool);
else
return ::MemAllocPtr(pool, size, 0);
}
void operator delete(void *mem)
// MemFreePtr handles both FS and Ptr allocs
{ if (mem) MemFreePtr(mem); }

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

// initialize static member 'pool' at startup
// to a fixed-size pool for Link objects
MEM_POOL Link::pool =
MemPoolInitFS(sizeof(Link), 10, 0);

void main()
{
// allocate a list Link with value 3
Link far *head = new Link(3);

delete head; // free the link
MemPoolFree(Link::pool); // and free pool

// init 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 string
MemPoolFree(var_pool); // and free pool
}

realloc

Changes the size of a memory block.

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

void *realloc(void *block, unsigned size);

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

Description The realloc function is the ANSI standard reallocator, which changes the size of a block to size bytes. The block parameter must be a pointer to a memory block previously returned by calloc, malloc, realloc, MemAllocPtr, MemReAllocPtr, MemAllocFS, or new. size may be smaller or larger than the original size, and the block is shrunk or expanded, respectively. If block is NULL, realloc behaves like malloc. If block is not NULL and size is zero, realloc returns NULL, and the old region is deallocated.

If the block is growing, the additional memory contents are uninitialized.

The size of the new block will be at least size, possibly larger due to alignment. You can determine the exact size of a block with MemSizePtr.

Important! The SmartHeap library defines the realloc 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 realloc 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 realloc calls go to SmartHeap by including shmalloc.h in each of your source modules — this header file defines realloc as a macro rather than as a function.

Comments The memory block may be moved to satisfy the allocation, that is, block might not be the same as the function’s result. If the block is moved, the original block is freed, so you should not reference the address block after realloc returns successfully.

In 16-bit x86 versions of SmartHeap, realloc is a far function returning a far pointer regardless of memory model. Therefore, you must use the large memory model or you must use the macro version of realloc, as described above, and declare pointers that store the function’s result as far. SmartHeap also overrides _frealloc, farrealloc, _expand, and _fexpand for compilers that define one or more of these functions.

Errors Error code Caused by

MEM_BAD_POINTER block isn’t a valid memory pointer.

MEM_OUT_OF_MEMORY There is insufficient memory.

MEM_NOREALLOC block was marked as “no realloc” by dbgMemProtectPtr.

MEM_WRONG_TASK block was allocated in a different task.

See also MemReAlloc, MemReAllocPtr, MemSizePtr

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

int StrTableSize = 0;

/* add an entry to a string table*/
char **AddEntry(char **pStrTable, char *val)
{
int i;

/* find a vacant entry in table */
for (;;)
{
/* search for an empty entry */
for (i = 0; i < StrTableSize; i++)
if (pStrTable[i] == NULL)
{
/* found a vacant entry: update */
pStrTable[i] = val;
return pStrTable;
}

/* all entries in use: expand table */
pStrTable = (char **)realloc(pStrTable,
sizeof(char *) * StrTableSize*2);
if (pStrTable)
{
memset(pStrTable + StrTableSize, 0,
sizeof(char *) * StrTableSize);
StrTableSize *= 2;
}
else
return NULL;
}
}

4.3 Error codes

This section lists SmartHeap error codes and the condition that causes each error. SmartHeap passes these codes to the error-handling callback you establish with MemSetErrorHandler.

Note “Runtime” or “Debug” after each error name indicates whether the error is detected by the SmartHeap Runtime Library or the SmartHeap Debug Library.

The “Errors” section of each entry of §4.2, “Function reference,” indicates which error conditions can arise for each individual function.

MEM_ALLOC_ZERO (Debug*)

You passed a block size of zero to MemPoolInitFS, MemAlloc, MemReAlloc, MemAllocPtr, or MemReAllocPtr, or you call MemPoolPreAllocate, specifying fixed-size blocks in a pool with a zero fixed-size block size.

MEM_BAD_BLOCK, MEM_BAD_FREE_BLOCK (Debug*)

Overwrite over an internal heap data structure entry. Detected by MemPoolWalk or MemPoolCheck; MemPoolCheck is called internally at every entry point when MEM_SAFETY_DEBUG is in effect.

MEM_BAD_BUFFER (Debug)

You passed an invalid buffer pointer or a buffer that is too small to MemPoolInfo, MemPoolFirst, MemPoolNext, or MemPoolWalk.

MEM_BAD_FLAGS (Debug)

You passed an invalid flags parameter to MemAlloc, MemReAlloc, MemAllocPtr, MemReAllocPtr, MemPoolInit, or MemPoolInitFS.

MEM_BAD_HANDLE (Debug*)

You passed an invalid memory handle parameter to MemFree, MemReAlloc, MemLock, MemUnlock, MemFix, MemUnfix, MemIsMoveable, MemSize, MemLockCount, or MEM_REFERENCE.

MEM_BAD_POINTER (Debug*)

You passed an invalid memory pointer parameter to calloc, malloc, free, realloc, MemFreePtr, MemSizePtr, MemFreeFS, MemCheckPtr, MemHandle, MemReAllocPtr, or MemPoolInfo.

* This error is sometimes detected in Runtime SmartHeap, but requires Debug SmartHeap to be detected reliably.

MEM_BAD_MEM_POOL (Debug*)

You passed an invalid memory pool parameter to MemPoolSetFloor, MemPoolInfo, MemAlloc, MemAllocFS, MemAllocPtr, MemPoolSetBlockSizeFS, MemCheckPtr, MemPoolSetPageSize, MemPoolSetCeiling, MemPoolWalk, MemPoolPreAllocate, MemPoolFree, MemPoolShrink, MemPoolSize, MemPoolCount, or MemPoolCheck.

MEM_BLOCK_TOO_BIG (Runtime)

You supplied a block size to MemPoolSetBlockSizeFS that exceeds the pool’s page size (possibly indirectly through MemPoolInitFS).

MEM_DOUBLE_FREE (Debug)

You passed a previously-freed memory pointer or handle as a parameter to SmartHeap.

MEM_EXCEEDED_CEILING (Runtime)

A SmartHeap function that allocates memory failed because it would have caused the pool size to exceed the limit established by MemPoolSetCeiling.

MEM_EXCEEDED_PROCESS_LIMIT (Runtime)

Process exceeded heap limit set with MemProcessSetHeapLimit.

MEM_FREE_BLOCK_READ (Debug)

A pointer was read from free memory, and your program attempted to read from that pointer.

MEM_FREE_BLOCK_WRITE (Debug)

A block was written to after it was freed. Detected by MemPoolCheck, or, when the safety level is MEM_SAFETY_DEBUG, by any SmartHeap entry point.

MEM_INTERNAL_ERROR (Debug*)

An internal SmartHeap error. Please report the error to MicroQuill Software Publishing, Inc. at (206) 402-9400.

MEM_LEAKAGE (Debug)

You called dbgMemReportLeakage and the function is reporting a memory block that has not been freed.

MEM_LOCK_ERROR (Runtime)

An erroneous call to MemLock, MemUnlock, MemFix, or MemUnfix. Caused either by a reference count underflow/overflow or by a handle type mismatch.

Macintosh You called a Mac memory manager API that SmartHeap does not support.

MEM_OUT_OF_BOUNDS_READ (Debug)

A pointer was read from outside the bounds of an allocated block, and your program attempted to read from that pointer.

MEM_OVERWRITE, MEM_UNDERWRITE (Debug)

SmartHeap detected an overwrite over the trailing or leading guards, respectively, that protect each memory block in the debug library. Detected by MemPoolCheck, by SmartHeap APIs that accept memory block (pointer or handle) parameters, or, when the safety level is MEM_SAFETY_DEBUG, by any SmartHeap entry point.

MEM_NOFREE, MEM_NOREALLOC (Debug)

You attempt to free or realloc a memory block previously marked as “no free” or “no realloc”, respectively, by dbgMemProtectPtr.

MEM_NOT_FIXED_SIZE (Debug)

You passed a pointer to a variable-size block to MemFreeFS, which accepts only fixed-size blocks.

MEM_OUT_OF_MEMORY (Runtime)

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

MEM_READONLY_MODIFIED (Debug)

A block previously marked as “read-only” by dbgMemProtectPtr was written to. Detected by MemPoolCheck, by SmartHeap APIs that accept memory block parameters, or, when safety level is MEM_SAFETY_DEBUG, by any SmartHeap entry point.

MEM_RESIZE_FAILED (Runtime)

You called MemReAlloc or MemReAllocPtr and specified MEM_RESIZE_IN_PLACE, but the block can’t be expanded in place.

MEM_TOO_MANY_PAGES (16-bit x86 platforms only) (Runtime)

You requested, from a single pool, allocations that require more than approximately 5,400 pages. Use MemPoolSetPageSize to increase the pool’s page size.

MEM_TOO_MANY_TASKS (16-bit Windows only) (Runtime)

You used the SmartHeap DLL concurrently with too many Windows module instances (tasks plus DLLs). The limit is approximately 340 tasks/DLLs for the debug DLL, and 3,200 tasks/DLLs for the Runtime DLL. This is a very unlikely error — it does not occur with the statically linked version of SmartHeap.

MEM_UNINITIALIZED_READ (Debug)

A pointer was read from uninitialized memory, and your program attempted to read from that pointer.

MEM_UNINITIALIZED_WRITE (Debug)

A pointer was read from uninitialized memory, and your program attempted to write through that pointer.

MEM_WRONG_TASK (16-bit Windows only) (Debug*)

You passed a non-shared memory pool, handle, or pointer to SmartHeap from a task that did not allocate that object.


SmartHeap Programmer’s Guide 355