Extending /proc/*/maps

Corinna Vinschen corinna-cygwin@cygwin.com
Thu May 12 18:43:00 GMT 2011

On May 12 13:53, Ryan Johnson wrote:
> On 12/05/2011 12:55 PM, Corinna Vinschen wrote:
> >>>    struct heap
> >>>    {
> >>>      heap *next;
> >>>-    void *base;
> >>>+    unsigned heap_id;
> >>>+    uintptr_t base;
> >>>+    uintptr_t end;
> >>>+    unsigned long flags;
> >>>    };
> >>We don't actually need the end pointer: we're trying to match an
> >No, we need it.  The heaps consist of reserved and committed memory
> >blocks, as well as of shareable and non-shareable blocks.  Thus you
> >get multiple VirtualQuery calls per heap, thus you have to check for
> >the address within the entire heap(*).
> The code which queries heap_info already deals with allocations that
> take multiple VirtualQuery calls to traverse, and only calls into
> heap_info for the base of any given allocation. 

However, at least heap 2 consists of multiple allocated memory areas,
which are separately VirtualAlloc'ed or NtMapViewOfSection'ed.  Therefore
the first VirtualQuery returns AllocationBase = BaseAddress = 0x20000
and the next VirtualQuery returns AllocationBase = BaseAddress = 0x30000.
However, all the memory from 0x20000 up to 0x230000 constitutes a single
start block in heap 2!

> CAVEAT: According to MSDN's documentation for HeapWalk, "a heap
> consists of one or more regions of virtual memory, each with a
> unique region index." During heap walking, wFlags is set to
> PROCESS_HEAP_REGION whenever "the heap element is located at the
> beginning of a region of contiguous virtual memory in use by the
> heap." However, "large block regions" (those allocated directly via
> VirtualAlloc) do not set the PROCESS_HEAP_REGION flag. If this
> PROCESS_HEAP_REGION flag corresponds to your (flags & 2), then we
> won't report any large blocks (however, it's documented to have the
> value 0x0001, with 0x0002 being PROCESS_HEAP_UNCOMMITTED_RANGE).

I created a test application with several heaps and I create large
blocks in two of them.  They also have the flags&2 value set.  The
problem for heap walk is to identify blocks with a valid address.  Keep
in mind that all subsequent blocks within an allocated heap area do
*not* have an addres, but only a size, with address == 0.  You only get
their address by iterating from the start block to the block you're
looking for and adding up all sizes of the blocks up to there.

Consequentially a start block of another VirtualAlloc'ed area needs a
marker that the address is valid.  That marker is the flags value 2.
Which is kind of weird, actually, since the existence of a non-0 address
in the block should have been enough of a hint that this is a start

As for the big blocks, they are apparently identified by the value in
the "Unknown" member of the DEBUG_HEAP_BLOCK structure.  Here's what I
figured out so far as far as "Unknown" is concerned:

   0x1000  All normal heaps
   0x3000  The process default heap (heap 0)
   0xc000  A low-frag heap
  0x10000  Heap 2, perhaps the meaning is "stack"?
  0x32000  Subsequently allocated block of a growable heap
 0x1e9000  Large block

I don't claim to understand the values, especially the reason for
setting several bits.

> >>>    heap *heaps;
> >>This is a misnomer now -- it's really a list of heap regions/blocks.
> >I don't think so.  The loop stores only the blocks which constitute
> >the original VirtualAlloc'ed memory regions.  They are not the real
> >heap blocks returned by Heap32First/Heap32Next.  These are filtered
> >out by checking for flags&  2 (**).
> Sorry, I cut too much context out of the diff. That's
> heap_info::heaps, which indeed refers to heap regions which we
> identified by checking flags&2 (that's why it needs the heap_id
> inside it now, where it didn't before) (++)

So you think something like heap_chunks is better?

> >>>+		heap *h = (heap *) cmalloc (HEAP_FHANDLER, sizeof (heap));
> >>>+		*h = (heap) {heaps, hcnt, barray[bcnt].Address,
> >>>+			     barray[bcnt].Address + barray[bcnt].Size,
> >>>+			     harray->Heaps[hcnt].Flags};
> >>>+		heaps = h;
> >>Given that the number of heap blocks is potentially large, I think
> >Not really.  See (**).  3 heaps ->  3 blocks, or only slightly more
> >if a growable heap got expanded.
> See (++). When I point my essentially-identical version of the code
> at emacs, it reports 8 heaps, each with 2-4 regions. The list
> traversed by fill_on_match has ~20 entries.

Oh, ok.  From my POV 20 is not a large number.  Ordering might take
more time than scanning.  I don't think it's worth the effort.


Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

More information about the Cygwin-patches mailing list