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 0372e598address 0372e598 found in_HEAP @ 36f0000HEAP_ENTRY Size Prev Flags UserPtr UserSize - state0372e598 0022 0000  0372e5a0 000f8 - (busy)? 3rdpartydll+1Trace: 7dfe0:000> dc 0372e598 lf8/4+2+40372e598 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 l110000001 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 20372e5a0 10000001 03707d5003707d50 20000001 193c8338193c8338 20000001 1868616818686168 20000001 204b7840204b7840 20000001 204b6df8204b6df8 20000001 204a7168204a7168 20000001 204a2d40204a2d40 20000001 14463df814463df8 20000001 1f8670301f867030 20000001 203d4588203d4588 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 _SPropValuemfcmapi!_SPropValuestruct _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.