7

I have a problem when running a testcase in debug-mode: I get a pop-up-box with the message "Unhandled exception at 0x7c812fd3 in Test.exe: 0xE0000003: 0xe0000003.". The code breaks in free.c:

void __cdecl _free_base (void * pBlock)
{
    int retval = 0;

    if (pBlock == NULL)
        return;

    RTCCALLBACK(_RTC_Free_hook, (pBlock, 0));

    retval = HeapFree(_crtheap, 0, pBlock);
    if (retval == 0)
    {
        errno = _get_errno_from_oserr(GetLastError());
    }
}

at line "retval =..." with _crtheap = 0x00df0000 and pBlock = 0x967c93d3. The call stack breaks at "kernel32.dll!7c812fd3() " and another entry further down in the call stack: ">msvcr100d.dll!_free_base(void * pBlock=0x967c93d3) Line 50 + 0x13 bytes".

I have googled quite a bit and the problem might come from freeing memory severel times. Despite this vague and messy description can anyone hint how to locate the problem ? and maybe how to fix it ?

What strikes me a bit odd is that I do not experience this when running the test in release-mode...

Kind regards, Svend

trincot
  • 317,000
  • 35
  • 244
  • 286
Svend Andreasen
  • 173
  • 1
  • 8
  • 2
    Usual reason for debug mode only errors is uninitialised variables. Maybe you are freeing a pointer which has never been given a value. – john May 01 '13 at 15:45
  • 4
    In release mode these checks are not done, hence why you only get notified in debug mode (the problem still exists in release, you just get lucky that it doesn't appear to cause any further bugs). Go up the stack trace until you get to a function that you wrote, and try to figure out what's wrong there (e.g. double-free or freeing an address that's not actually been allocated). – Cameron May 01 '13 at 15:45
  • Can you give a bit more detail? What sort of object is being freed? Is it a smart pointer for example – John Sibly May 01 '13 at 15:47
  • 2
    You give no hint as to your application, but using RAII (via std::vector, std::unique_ptr, std::shared_ptr, etc.) to manage all your resources means that you will eliminate virtually all errors related to releasing resources. If you have a pointer going beyond the bounds of the array, RAII won't stop that, but checked containers like std::vector can detect that in debug mode. My guess is that it only fails in debug b/c it's only checking some failure conditions in debug mode or that the corruption doesn't happen in release mode because code/data is different and in different places in memory. – metal May 01 '13 at 15:50
  • 1
    A double free does seem like a likely candidate. One thing you can try to do is look at the address being freed. Are you very lucky and it's the same between runs (so that you can set a watchpoint on it, for example)? Or can you try to identify it in relation to some other object? – huskerchad May 01 '13 at 16:03
  • @metal Actually, `std::shared_ptr` is a good candidate for causing multiple frees. – James Kanze May 01 '13 at 16:38
  • You may get some usful hints from here http://msdn.microsoft.com/en-us/library/974tc9t1.aspx – j.holetzeck May 01 '13 at 16:40
  • If you are running on Microsoft Windows, you can utilize Application Verifier and your debugger to catch heap corruptions, double frees, etc in "unmanaged" (non .Net) code. You can get Application Verifier for free from: http://www.microsoft.com/en-us/download/details.aspx?id=20028 – StarPilot May 01 '13 at 18:20
  • see above link for `_CRTDBG_CHECK_ALWAYS_DF`: "Causes _CrtCheckMemory to be called at every allocation and deallocation. This slows execution, but catches errors quickly." – j.holetzeck May 01 '13 at 18:22
  • @JamesKanze, do you mean that *misuse* of shared_ptr is a good candidate for causing multiple frees? If you *always* assign your new/malloced memory to an RAII enabler and *always* let it do your cleanup for you, how can you get multiple frees? – metal May 01 '13 at 19:44
  • @metal Obviously, if something causes problems, it is being misused. The problem with `shared_ptr` is that it is too easily misused. You usually can't avoid raw pointers (starting with `this`). In most cases, you can't easily avoid cycles, and you generally don't want the more or less non-deterministic object lifetime which `shared_ptr` gives you. There are exceptional cases where its use is valid, but I generally avoid it. – James Kanze May 02 '13 at 08:01
  • First of all - thank you for all your replies. – Svend Andreasen May 02 '13 at 12:19
  • @JohnSibly: unfortunately I don't have any idea what kind of object that is being freed - all I have is a memory address :( – Svend Andreasen May 02 '13 at 12:30
  • @huskerchad: maybe a stupid question but would you know how I can set a watch point to an address when I do not know what kind object it is holding ? – Svend Andreasen May 02 '13 at 12:34
  • @JamesKanze, in the smart pointer utopia Herb Sutter lives in and that I try to inhabit when I can, raw pointers -- including `this` -- are used for non-owning observation, which boils down to not deleting them explicitly. If double deletion is the problem here, thorough use of RAII (including smart pointers) can help. If `shared_ptr` isn't the right tool for the job in a particular application, that's fine, but there's no need to throw the baby out with the bath water. It has its right and safe uses and is not always as problematic as you make it out to be, IME. – metal May 02 '13 at 19:55
  • @metal Two comments: first, `this` is often the "owning" pointer in my code; at least `delete this;` is one of the more common ways of terminating object lifetime. Second, there are right and safe uses of `shared_ptr` (although I find invasive reference counting significantly safer, and continue to use my own `RefCntPtr`, which dates to long before Boost). But globally, it is still a tool for special cases, and not something general which should be used systematically. – James Kanze May 03 '13 at 07:42
  • does the pointer pBlock looks plausible? what is the Data in this pointer. May be some special values like 0xfeeefeee ? – vlad_tepesch May 03 '13 at 12:22
  • @JamesKanze, in the aforementioned place I like to call Sutteria (capital of Alexandrescopolis), the need for `delete this` is a very rare thing. The vast majority of cases get handled by something like std::unique_ptr which owns the instance of C and is responsible for cleaning it up. That being said, I too use invasive reference counting when appropriate, but ["ownership in a package"](http://flamingdangerzone.com/cxx11/2012/08/15/rule-of-zero.html), like the standard RAII classes provide, is my go-to idiom. – metal May 03 '13 at 13:19
  • @metal The need for `delete this;` is patent. The object has a lifetime defined by the application logic, not some non-deterministic decision based on who happens to have a pointer to it. Depending on the program logic, you will use `delete this;`, or it will be the transaction manager which does the delete (at the end of the transaction, because the object has requested that it be deleted). It is the program logic which determines lifetime. – James Kanze May 03 '13 at 13:49

1 Answers1

-3

Have you tried to run these testcases under visual studio debugger? Debugger should catch this exception and you can verify call stack and locate where issue is.

Zuljin
  • 2,612
  • 17
  • 14
  • The exception is occurring in `_free_base`, he already knows this. But the debugger is not catching the issue (i.e. heap corruption that occurred earlier) – Ben Voigt May 01 '13 at 16:44
  • If that is the case then he should just use debugger and stepping go through all testcases code and locate part that generate exception. – Zuljin May 01 '13 at 17:04
  • Wow. This kind of naive advice can only come from someone who has never experienced an action-at-a-distance bug. I envy you. – Ben Voigt May 01 '13 at 17:07
  • 1
    Ben, probably you are right that simple stepping won't be enough. But this is a first think he should do. If this doesn't help then he could try setting write access breakpoints on heap. If playing with debugger won't be enough then there is few tools that could help like Application Verifier or GFlags and PageHeap from Debugging Tools for Windows. Sometimes also tools for detecting memory leaks/corruption like Rational Purify could help as well. – Zuljin May 01 '13 at 17:59