Paul
Paul

Reputation: 6911

Given a pointer, find the heap block where it resides

An example:

char *p1 = HeapAlloc(GetProcessHeap(), 0, 12); // returns 0x1234
char *p2 = p1 + 7;

// ...

void *p;
size_t size;
if(GetHeapBlock(p2, &p, &size))
    printf("%p (%zd)", p, size); // should print "0x1234 (12)"

How can I implement the GetHeapBlock function above?

I looked at the Proc Heap Viewer, HeapMemView programs, but the information that they display is not exactly what I expect. e.g. the pointers are sometimes lower, and the sizes are larger, so for the example above they could show 0x1200 of size 256. Also, both show different information.

In general, I could call GetProcessHeaps, and for each heap call HeapValidate for every pointer, starting from the input getting lower. Then I could call HeapSize. But this sounds extremely inefficient. Is there a better solution?

P.S. I need this for diagnostics, not for production, so a solution which is not 100% reliable/performant is acceptable.

Upvotes: 0

Views: 370

Answers (1)

theB
theB

Reputation: 6738

How about using HeapWalk, and walking your process heap like this:

HANDLE hHeap = GetProcessHeap();
char *p1 = (char*)HeapAlloc(hHeap, 0, 12);
cout << "P1: " << static_cast<void*>(p1) << endl;
char *p2 = p1 + 7;

PROCESS_HEAP_ENTRY entry;
entry.lpData = NULL;

BYTE regionIndex = 0xFF;

bool found = false;
while (!found && HeapWalk(hHeap, &entry) != FALSE)
{
    if ((entry.wFlags & PROCESS_HEAP_REGION) != 0)
    {
        if (p2 < entry.Region.lpLastBlock && p2 >= entry.Region.lpFirstBlock)
        {
            cout << "Heap Region" << endl;
            cout << "First Block: " << entry.Region.lpFirstBlock << endl;
            cout << "Overhead: " << entry.cbOverhead << endl;
            cout << "Size: " << entry.cbData << endl;
            cout << "Data: " << entry.lpData << endl;
            regionIndex = entry.iRegionIndex;
        }
        else
        {
            // should work to skip to the last block in the region.  YMMV. Didn't test this scenario.
            entry.lpData = entry.Region.lpLastBlock;
        }

    }
    else if ((entry.wFlags & (PROCESS_HEAP_ENTRY_BUSY | PROCESS_HEAP_ENTRY_MOVEABLE)) != 0)
    {
        if (entry.iRegionIndex == regionIndex)
        {
            if (p2 >= entry.lpData && p2 < ((char*)entry.lpData + entry.cbData))
            {
                cout << "Heap Block" << endl;
                cout << "Heap Data: " << entry.lpData << endl;
                cout << "Block hMem: " << entry.Block.hMem << endl;
                cout << "Block Size: " << (int)entry.cbData << endl;
                cout << "Overhead: " << (int)entry.cbOverhead << endl;
                found = true;
            }
        }
    }
}

Technically this sample is C++, but the idea remains the same even for pure C. (I'm just lazy and I already had a C++ scratch program, and std::cout is convenient.) Basically you initialize a PROCESS_HEAP_ENTRY structure with it's lpData set to NULL, to start the walk at the beginning of the heap. See the MSDN HeapWalk() article for more information.

When I run this on my system I get:

P1: 00379FC0
Heap Region
First Block: 00360598
Overhead:
Size: 1416
Data: 00360000
Heap Block
Heap Data: 00379FC0
Block hMem: 0001A000
Block Size: 12
Overhead: 28

Edited to add: You could also use this method to dump the entire process heap.

Upvotes: 1

Related Questions