HEAP[MyApp.exe]: HEAP: Free Heap block bf33b8 modified at bf3538 after
it was freed
This occurs during the malloc call, 5 or 6 calls deeper in
msvcr90d.dll and then ntdll.dll.
I don't see anything in my code trying to modify bf3538.
Any ideas what exactly is going on here? and how to investigate this
with the VS2008 debugger? I can reproduce the problem consistently.
Thanks,
Andrew.
It occurs to me that the modification might not have occured during
the malloc call, but only detected then. Does malloc automatically
run some kind of heap corruption check? Is there some way to run this
manually and is there documentation on MSDN about how this check
works?
Thanks,
Andrew.
...so I have added:
HANDLE procHeap = GetProcessHeap();
HeapValidate(procHeap, 0, 0);
at various key points in the code, and sometimes HeapValidate breaks
and finds the corruption.
So it is clear that something is causing a memory overwrite previous
to this code getting called.
Is there some way set a break point at a specific memory address that
triggers when someone writes to the address?
Are there any other techniques that someone can use to track down a
memory overwrite using VS2008?
Thanks,
Andrew.
The easiest way to find the culprit is to set every pointer to NULL
immediately after you free/delete. That will halt the program
immediately if the pointer is reused.
I've tried setting the pointers to 0 after free/delete, but it does
not catch the corruption.
Is there a way I can make the process break at the time the write is
made to the freed memory?
Alternatively, is there a way to inspect the contents of the memory at
a given location (ie 0xbf3538 in this case)? If I can see what is
being written perhaps I can guess who is writing it.
Thanks,
Andrew.
If you know the address (i.e. it's constant, or at least
deterministic per run), absolutely. Do the following:
1) Start your app, either with F5 (run) or F10 (single-step to the top
of main()/winmain()). Note: I'm going to list keyboard shortcuts for
Visual C++ 6, because that's what I use.
2) Determine address to place breakpoint at, e.g. 0x12345678.
3) Hit alt-F9 to pull up breakpoints window. In it, select new -> new
data breakpoint. (If you don't have that option, then you need to
enable Visual Studio -> Tools -> Options -> Debugging -> [x] Enable
address-level debugging. Then, you should see the 'new data
breakpoint' option.
4) Insert the address from step #2 in the breakpoint window. IIRC,
x86 processors allow you to breakpoint up to 4 addresses at once
for free; more than that will cause terminal slowdowns.
5) Resume running your app (F5, etc)
Once set, breakpoints will work as long as it's *your* code that's
writing to that address. But, writes done by the Win32 kernel code,
e.g. ReadFile() --
http://msdn.microsoft.com/en-us/library/aa365467(VS.85).aspx -- won't
be caught by the breakpoint, because the kernel has a different view
of your address space.
Also, take note that if you stop debugging and re-run your app,
normal breakpoints on a line of code are remembered by DevStudio. But,
address-level breakpoints are auto-disabled when you stop and re-run.
They're not deleted, just disabled. I don't know of any options in
DevStudio to make it re-enable those breakpoints.
Nathan Mates
--
<*> Nathan Mates - personal webpage http://www.visi.com/~nathan/
# Programmer at Pandemic Studios -- http://www.pandemicstudios.com/
# NOT speaking for Pandemic Studios. "Care not what the neighbors
# think. What are the facts, and to how many decimal places?" -R.A. Heinlein
Hello,
At runtime, you can position a breakpoint on a memory address change
event, go to "Debug|New Breakpoint...|New Data Breakpoint...". But your
program must run for this option to be available.
Hope this help
Cathy
Yes, see my earlier posting to this thread.
>Alternatively, is there a way to inspect the contents of the memory at
>a given location (ie 0xbf3538 in this case)? If I can see what is
>being written perhaps I can guess who is writing it.
Yes. In DevStudio, go to Debug -> Windows -> Memory -> Memory 1
(Alt-6 in VC++6 keyboard shortcuts). You can only inspect memory via
that window when your app is paused.
Once again, you may need to turn on address-level debugging to get
the memory view window. In DevStudio, make sure Tools -> Options... ->
Debugging -> General -> [x] Enabled address-level debugging is
checked.
> If you know the address (i.e. it's constant, or at least
> deterministic per run), absolutely. Do the following:
Actually, sorry guys, I dont know what address it is going to happen
at, so I cant set a hardware breakpoint on it. It changes every
time. Although I do have it consistently crashing.
I memory dumped the region in WinDbg (which I am using for the first
time) and I see:
00c13700 ee fe ee fe ee fe ee fe-ee fe ee fe ee fe ee
fe ................
00c13710 ee fe ee fe ee fe ee fe-00 00 00 00 ee fe ee
fe ................
00c13720 ee fe ee fe ee fe ee fe-ee fe ee fe ee fe ee
fe ................
You can see the 32 bit zero? That is not meant to be there, and it is
what HeapValidate is complaining about.
I suppose the 0xFEEE is some kind of patten placed in freed memory by
the debug libraries?
Any other ideas how I can track this down?
Thanks,
Andrew.
So it is not linked to any var?
What do you mean linked to a var? Someone is writing a 32-bit 0 in
the middle of a freed block of memory, and then at some point later
when I call HeapValidate it notices this. I need to figure out what
code is writing the 0. All I have is the memory address that it is
written to, but this changes after every run of the program so I cant
set a breakpoint.
-Andrew.
>00c13700 ee fe ee fe ee fe ee fe-ee fe ee fe ee fe ee
>fe ................
>00c13710 ee fe ee fe ee fe ee fe-00 00 00 00 ee fe ee
>fe ................
>00c13720 ee fe ee fe ee fe ee fe-ee fe ee fe ee fe ee
>fe ................
>You can see the 32 bit zero? That is not meant to be there, and it is
>what HeapValidate is complaining about.
Yep, I'd complain about that too. If you look at
http://en.wikipedia.org/wiki/Magic_number_(programming) , you'll see
that 0xFEEEFEEE is freed memory. Something in your app is writing to
memory after it told the system that it's done with it. It's also in
the *middle* of a block, which to me suggests that if you've NULL'd
the pointer to the start of the block after freeing it (as you claim),
you're still holding on to another pointer -- e.g. a pointer to
something within your structure.
Here are some debugging strategies:
1) As much as possible, try and get this to happen consistently and at
the same address. Then, you can use a HW breakpoint to see who's
writing to 0x00c1371C (or whatever it ends up being.) If you run
debug, it should reduce the amount of randomness in your app by
filling allocated memory with a consistent pattern. Also, turn on
project properties -> Configuration Properties -> C/C++ -> Code
Generation -> Basic Runtime Checks to 'Both'.
2) Look at http://msdn.microsoft.com/en-us/library/5at7yxcs.aspx , and
call _CrtSetDbgFlag with at least _CRTDBG_CHECK_ALWAYS_DF . That'll
force (in a debug build) the C Runtime libs to check memory for errors
each allocation/deallocation call. This may reduce your app to a
crawl, especially if you allocate/deallocate lots of memory. You may
want to turn this on partway thru your app's running, if you have
something that seems to trigger this.
3) If you've got something that seems to trigger this behavior,
sprinkle lots of calls to _ASSERTE(_CrtCheckMemory()); in your
code after your trigger. See
http://msdn.microsoft.com/en-us/library/e73x0s4b(VS.71).aspx
for more info.
4) Worst comes to worst, write a wrapper function for free/delete that
logs out the line of code doing the deallocation and what the pointer
is. Then, get it to stomp the 0 over memory. Look at your logs, and
find pointers close to where the 0 was written. See if something in
your code could be holding onto a pointer to something in those
blocks.
C/C++ require you to know what you're doing w/ memory access.
When your code releases a block, it MUST not touch it again.
You could spread HeapValidate calls through your code to narrow down the
location.
--
Dee Earley (dee.e...@icode.co.uk)
i-Catcher Development Team
iCode Systems
Indeed. On one occasion, when all else failed, I set a thread to spin
calling _CrtCheckMemory for the life of the program. Slows it down
terribly though; It's certainly not something to leave in release.
Also consider the options available via _CrtSetDbgFlag:
http://msdn.microsoft.com/en-us/library/5at7yxcs(VS.71).aspx