Recognizing MAPI Allocated Memory

Continuing our look at lessons learned from James’ article on the MAPI memory leak, we look at the memory that James recognized as MAPI properties. How did he figure this out? As a refresher, here’s what the memory looked like:

0:000> !heap -p -a 0372e598 
    address 0372e598 found in
    _HEAP @ 36f0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0372e598 0022 0000  [07]   0372e5a0    000f8 - (busy)
          ? 3rdpartydll+1
        Trace: 7dfe
0:000> dc 0372e598 lf8/4+2+4
0372e598  000d0022 001807d6 10000001 03707d50  "...........P}p.
0372e5a8  0fff0102 00000000 00000018 203d4590  .............E= 
0372e5b8  001a001e 00000000 1f867038 00000000  ........8p......
0372e5c8  30070040 00000000 500075a0 01c8cfa5  @..0.....u.P....
0372e5d8  300b0102 00000000 00000010 14463e00  ...0.........>F.
0372e5e8  0037001f 00000000 204a2d48 00000000  ..7.....H-J ....
0372e5f8  0037001e 00000000 204a7170 00000000  ..7.....pqJ ....
0372e608  003d001f 00000000 204b6e00 00000000  ..=......nK ....
0372e618  003d001e 00000000 204b7848 00000000  ..=.....HxK ....
0372e628  0e060040 00000000 4a1c9600 01c8cfa5  @..........J....
0372e638  00390040 00000000 55de88e0 01c8cfa5  @.9........U....
0372e648  1035001e 00000000 18686170 00000000  ..5.....pah.....
0372e658  0c1f001f 00000000 193c8340 00000000  ........@.<.....
0372e668  0c1f001e 00000000 03707d58 00000000  ........X}p.....
0372e678  00170003 00000000 00000001 00000000  ................
0372e688  0e1b000b 00000000 00000001 00000000  ................
0372e698  abababab abababab 00007dfe 00000000  .........}......

Recall that James and I discussed how the !heap extension tries running dps against the beginning of the user porion of the memory allocation (0x0373e5a0 in this case) on the hopes it might point to an object vtable. In this case, it does point into a module, but it’s not a vtable. How do we know? Our first big clue is the address, 10000001, has very few bits in it. Two to be exact. Whenever you see a 32 bit value in memory that has only a handful of bits set in it, there’s a really good chance it’s a flag. Our second clue comes when we run dps against the address, we see that if it were a function pointer, it’s pointing at a different module, which you shouldn’t see in a vtable:

0:000> dps 10000001 l1
10000001  0300905a MSOINTL+0x75905a

Our third clue, and, for me, the nail in the coffin, is that 10000001 isn’t a multiple of 4. I have never seen a vtable that wasn’t 4 byte aligned.

So if this memory isn’t an object, what is it? If you spend some time allocating memory with MAPIAllocateBuffer and MAPIAllocateMore, then looking at the corresponding heap allocations, you’ll see that those functions always allocate 8 bytes more than you ask for. If you look at those extra 8 bytes, you’ll probably notice that allocations made by MAPIAllocateBuffer always start with the 4 bytes 10000001, and allocations made by MAPIAllocateMore always start with the 4 bytes 20000001. The second 4 bytes on these allocations look like pointers into the heap. We can walk these pointers and see the chain of allocations that MAPIFreeBuffer will walk when it is asked to free this memory. Since the pointer to the next entry happens to be in the same offset as a Blink in the LIST_ENTRY structure, we can abuse the dl (Display Linked List) command to output our list:

0:000> dlb 0372e5a0 f 2
0372e5a0  10000001 03707d50
03707d50  20000001 193c8338
193c8338  20000001 18686168
18686168  20000001 204b7840
204b7840  20000001 204b6df8
204b6df8  20000001 204a7168
204a7168  20000001 204a2d40
204a2d40  20000001 14463df8
14463df8  20000001 1f867030
1f867030  20000001 203d4588
203d4588  20000001 00000000

So – that’s an interesting digression, but we still haven’t figured out what this memory is. From the caller’s perspective, the allocation began at 0372e5a8 (8 more than the address MAPI got from the heap), and appears to follow a 10 byte pattern from there. Notice that the entries in the first column tend to end in 0102, 001E, 0040, 0003, etc. If you’ve been working with MAPI for a while, you’ll recognize these as PT_BINARY, PT_STRING8, PT_SYSTIME, and PT_LONG. So that first column consists of property tags! Do we know of any MAPI structures that are 0x10 bytes long and start with a property tag? Turns out we do:

0:000> dt -v _SPropValue
struct _SPropValue, 3 elements, 0x10 bytes
   +0x000 ulPropTag        : Uint4B
   +0x004 dwAlignPad       : Uint4B
   +0x008 Value            : union _PV, 28 elements, 0x8 bytes

And if we try casting this memory as _SPropValue, we see everything lines up quite nicely, so this must be an array of type _SPropValue. The output is rather long – I’ll leave it as an exercise for the reader. Remember to use –a and –r!

Next: a brief look at UST and 64 bit machines.

Comments (3)

  1. Digging more into lessons learned from James’ blog on analyzing memory usage (my first two articles are

  2. I think this will be the last article to come from James’ post on debugging MAPI (previous posts here

  3. Working with a customer the other day, I went looking for my blog post discussing the fact that MAPI