On 12/05/2011 11:09 AM, Corinna Vinschen wrote:
On May 12 14:10, Corinna Vinschen wrote:
On May 11 21:31, Corinna Vinschen wrote:
On May 11 13:46, Ryan Johnson wrote:
Given that Heap32* has already been reverse-engineered by others,
the main challenge would involve sorting the set of heap block
addresses and distilling them down to a set of allocation bases. We
don't want to do repeated linear searches over 50k+ heap blocks.
While the base address of the heap is available in
DEBUG_HEAP_INFORMATION, I don't see the size of the heap.  Maybe it's in
the block of 7 ULONGs marked as "Reserved"?  It must be somewhere.
Assuming just that, you could scan the list of blocks once and drop
those within the orignal heap allocation.  The remaining blocks are big
blocks which have been allocated by additional calls to VirtualAlloc.
After some debugging, I now have the solution. [...]
Here's a prelimiary patch to fhandler_process.cc which takes everything
into account I have learned in the meantime.  For instance, there are
actually heaps marked as shareable.  Please have a look.  What's missing
is the flag for low-fragmentation heaps, but I'm just hunting for it.
I like it. Detailed comments below.

+/* Known heap flags */
+#define HEAP_FLAG_NOSERIALIZE  0x1
+#define HEAP_FLAG_GROWABLE     0x2
+#define HEAP_FLAG_EXCEPTIONS   0x4
+#define HEAP_FLAG_NONDEFAULT   0x1000
+#define HEAP_FLAG_SHAREABLE    0x8000
+#define HEAP_FLAG_EXECUTABLE   0x40000
Would it make sense to put those in ntdll.h along with the heap structs that use them?

    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 unknown allocation base against heap region bases. The code which traverses VM allocations should query heap_info at most once per allocation (for example, it only looks up the file name of cygwin1.dll once even though the latter has 12 entries in /proc/*/maps).

    heap *heaps;
This is a misnomer now -- it's really a list of heap regions/blocks.

+               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 it makes sense to build a sorted list. That way, each query examines only one heap block (deleting it unless it was above the queried address). I have ready-but-unsent a patch which does this to the checked-in version of the code. Shall I send it?

-  char *fill_if_match (void *base, char *dest )
+  char *fill_if_match (void *base, ULONG type, char *dest )
    {
-    long count = 0;
-    for (heap *h = heaps; h&&  ++count; h = h->next)
-      if (base == h->base)
+    for (heap *h = heaps; h; h = h->next)
+      if ((uintptr_t) base>= h->base&&  (uintptr_t) base<  h->end)
        {
-         __small_sprintf (dest, "[heap %ld]", count);
+         char *p;
+         __small_sprintf (dest, "[heap %ld", h->heap_id);
+         p = strchr (dest, '\0');
+         if (!(h->flags&  HEAP_FLAG_NONDEFAULT))
+           p = stpcpy (p, " default");
+         if ((h->flags&  HEAP_FLAG_SHAREABLE)&&  (type&  MEM_MAPPED))
+           p = stpcpy (p, " share");
+         if (h->flags&  HEAP_FLAG_EXECUTABLE)
+           p = stpcpy (p, " exec");
+         if (h->flags&  HEAP_FLAG_GROWABLE)
+           p = stpcpy (p, " grow");
+         if (h->flags&  HEAP_FLAG_NOSERIALIZE)
+           p = stpcpy (p, " noserial");
+         stpcpy (p, "]");
          return dest;
        }
      return 0;
Do you actually encounter requests which fall inside a heap region rather than at its start? I have not seen this in my experiments, and if you have it is almost certainly a bug in format_process_maps' allocation traversal.

Also, are there ever shareable-but-not-mem_mapped segments? If not, we could probably remove 'type.'

Ryan

Reply via email to