Platform SDK: MAPI

MAPIDBG.INI [Memory Management] Section

The entries in this section control debugging features in the MAPI memory allocator.

VirtualMemory = 0|1|4
If this entry is nonzero, memory allocations made through MAPI are surrounded by unaddressable memory on either side. This causes code that accesses memory outside the allocated block to fail immediately instead of corrupting memory and can be very helpful in isolating memory corruption bugs. If this entry is set to 4, the returned address is guaranteed to be aligned on a 4-byte boundary; if it is 1, the address of the returned memory block is unaligned. The default value is 0 — a normal heap is allocated.
AssertLeaks = 0|1
If this entry is set to 1, MAPI asserts if any memory allocated using the MAPI allocators has not been freed at the time MAPI is shut down. This is usually at the last MAPIUninitialize call; if the application fails to uninitialize MAPI, it occurs when the MAPI DLL is unloaded. The default value is 1 — generates asserts.
DumpLeaks = 0|1
If this entry is set to 1, MAPI outputs debug trace information regarding memory allocated using the MAPI allocators that were not freed by the time MAPI was shut down. The information includes a stack traceback (for Win32 only), size and location of the memory block, order in which the block was allocated, and the block's name (for internal MAPI allocations only). The default value is 1 — writes traces.
FillByte = 0xNN
This entry specifies the hexadecimal value to use for filling memory in the FillMemory entry. The default value is 0xFE.
FillMemory = 0|1
If this entry is set to 1, all memory blocks allocated by MAPI are filled with a fill byte after they're allocated and after they're freed. The default value is 1 — fills blocks.
SharedMemMaxSize = number of bytes
This entry limits the size of the MAPI shared memory area. It can be used to force allocation failures. The default value is 0 — the area is as big as necessary.

Anyone using the Microsoft RPC libraries who needs to use virtual allocation flags should set the VirtualMemory entry to 4 in both the [General] and [Memory Management] sections of MAPIDBG.INI. This includes anyone using EMSMDB.DLL or EMSABP.DLL. Microsoft RPC requires memory allocators to align memory at least as well as the operating system's allocator. The MAPI Virtual Memory allocator aligns on 4-byte boundaries when set to 4. Setting VirtualMemory to 1 does not do this in order to catch even single-byte overwrites immediately.

Enabling virtual allocation increases the MAPI subsystem's demand for system resources. On Win32, MAPI uses 64K of virtual address space for each allocation. On Win16, MAPI uses the GlobalAlloc function for each allocation, so it is possible to run out of selectors. Depending on the overall load your test scenario places on the system, you may need to narrow down the scenario enough to reproduce the problem without running out of system resources.

Clients and service providers can trace memory leaks by setting the DumpLeaks entry in the [Memory Management] section to 1, MAPI produces debug trace output for each leaked block of memory. For each leaked block, MAPI lists:

One technique for turning the stack traceback into a usable symbolic trace is to save the debug output to a text file, get your application back into the WINDBG debugger in a steady state, and convert the hexadecimal numbers to symbols using the 'list near' command. This command prints the nearest symbols before and after a given address. It is helpful to use a macro in your preferred editor to convert the MAPI trace, which looks like this:

Memory leak 'Proxy/Stub Object' in MAPIX Internal Heap @ 004E0770, 
    Allocation #18, Size: 48
[0] 6C4C3B2F 
[1] 6C4C401D 
[2] 77CF7AB7 
[3] 77D30E30 
[4] 77CC9076 
 

into a string of "list near" commands that looks like this (it gives you the closest symbol before and after the address):

> ln 6C4C3B2F; ln  6C4C401D; ln 77CF7AB7; ln 77D30E30; ln 77CC9076
 

When run in the WINDBG command window, this string produces a list of symbols like the following (there are two symbols for each address, the first is almost always the one you want):

MAPI32!operator new(unsigned int)+0x2f
MAPI32!operator delete(void *)-0x31
MAPI32!StdPSFactory::CreateProxy(IUnknown *, const _GUID &, 
    IRpcProxyBuffer * *, void * *)+0xbd
MAPI32!StdPSFactory::CreateStub(const _GUID &, IUnknown *, IRpcStubBuffer * *)-0xe3
OLE32!?CreateInterfaceProxy@CRemoteHdlr@@AAEPAVCPSIX@@ABU_GUID@@PAPAXPAJ@Z+0x7d
OLE32!?CreateInterfaceStub@CRemoteHdlr@@AAEPAVCPSIX@@ABU_GUID@@PAJ@Z-0xc1
OLE32!_IEnumUnknown_RemoteNext_Proxy@16+0xf
OLE32!_IEnumUnknown_RemoteNext_Thunk@4-0x6
OLE32!?AddRef@CRemoteHdlr@@UAGKXZ+0
OLE32!?GetRH@CStdIdentity@@AAEPAUIRemoteHdlr@@XZ-0x11
 

MAPI does not expose an API to trigger an allocation dump.

It is most efficient to address memory leaks as they occur instead of waiting until there is a large number.