How can you track memory across DLL boundaries

I want to execute performance metrics at runtime, so I wrote a memory tracker based on the overload of new and delete . This basically allows you to track your distributions on the heap and analyze everything about them - fragmentation, size, time, number, stop code, etc. But it has 2 fatal flaws: it cannot track the memory allocated in other DLLs, and when the ownership of objects is transferred to the DLL or vice versa. And some smaller flaws: if the user uses malloc instead of new , he is not tracked; or if the user sets the class new / delete .

How can I eliminate these shortcomings? I think that, in my opinion, this is happening incorrectly by overloading new / delete , is there a better way?

+4
source share
3 answers

The right way to implement this is to use workarounds and a separate tool that works in its own process. The procedure looks something like this:

  • Create memory allocation in a remote process.
  • Put the code for the small loader that will load your DLL.
  • Call the CreateRemoteThread API, which will launch your bootloader.
  • Inside the loaded dll, workarounds (interceptors, interceptors) are set to the alloc / dealloc function.
  • Handle calls, track activity.

If you implement your tool in this way, it will not matter from which DLL or directly from exe the memory allocation procedure is called. In addition, you can track actions from any process, it is not necessary that you compiled yourself.

MS Windows allows checking the contents of the virtual address space of a remote process. You can summarize the use of the virtual address space, which was thus collected in a histogram, as shown below:

enter image description here

In this picture you can see how many virtual distributions of what size exist in your target process.

enter image description here

The figure above shows an overview of the use of virtual address space in 32-bit MSVC DevEnv. The blue bar means the comma part of the emory, the magenta bar is reserved. Green is an unallocated part of the address space.

You can see that the lower addresses are quite fragmented, but the middle area is not. Blue lines at high addresses are various DLLs that are loaded into the process.

+4
source

You must find the common memory management routines that are called by new / delete and malloc / free and intercept them. This is usually malloc / free , but check to be sure.

On UNIX, I would use LD_PRELOAD with some library that re-executed these procedures. On Windows you should be a little hacky, but this link seems to give a good description of the process. This basically assumes that you are using Explanations from Microsoft Research .

0
source

The transfer of ownership of objects between modules is fundamentally wrong. It appeared with your custom dispenser, but there are many other cases that will also fail:

  • compiler updates and recompilation of only some DLLs
  • mix compilers from different suppliers
  • static linking runtime library

Just to name a few. Free each object from the same module that allocated it (often by exporting a delete function, such as IUnknown::Release() ).

0
source

All Articles