开发者

_DebugHeapDelete Access Violation at termination

I'm getting a weird access violation at the end of my main whose cause I'm having some difficulties finding.

When shutting down my application I get an access violation in the following:

xdebug

        // TEMPLATE开发者_如何学JAVA FUNCTION _DebugHeapDelete
template<class _Ty>
    void __CLRCALL_OR_CDECL _DebugHeapDelete(_Ty *_Ptr)
    {   // delete from the debug CRT heap even if operator delete exists
    if (_Ptr != 0)
        {   // worth deleting
        _Ptr->~_Ty();
        // delete as _NORMAL_BLOCK, not _CRT_BLOCK, since we might have
        // facets allocated by normal new.
        free(_Ptr); // **ACCESS VIOLATION**
        }
    }

Stack trace:

>   msvcp100d.dll!std::_DebugHeapDelete<void>(void * _Ptr)  Line 62 + 0xa bytes C++
    msvcp100d.dll!std::numpunct<char>::_Tidy()  Line 190 + 0xc bytes    C++
    msvcp100d.dll!std::numpunct<char>::~numpunct<char>()  Line 122  C++
    msvcp100d.dll!std::numpunct<char>::`scalar deleting destructor'()  + 0x11 bytes C++
    msvcp100d.dll!std::_DebugHeapDelete<std::locale::facet>(std::locale::facet * _Ptr)  Line 62 C++
    msvcp100d.dll!std::_Fac_node::~_Fac_node()  Line 23 + 0x11 bytes    C++
    msvcp100d.dll!std::_Fac_node::`scalar deleting destructor'()  + 0x11 bytes  C++
    msvcp100d.dll!std::_DebugHeapDelete<std::_Fac_node>(std::_Fac_node * _Ptr)  Line 62 C++
    msvcp100d.dll!_Fac_tidy()  Line 41 + 0x9 bytes  C++
    msvcp100d.dll!std::_Fac_tidy_reg_t::~_Fac_tidy_reg_t()  Line 48 + 0xe bytes C++
    msvcp100d.dll!std::`dynamic atexit destructor for '_Fac_tidy_reg''()  + 0xf bytes   C++
    msvcp100d.dll!_CRT_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved)  Line 415 C
    msvcp100d.dll!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved)  Line 526 + 0x11 bytes  C
    msvcp100d.dll!_DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved)  Line 476 + 0x11 bytes   C

Anyone got any ideas as to what might cause this?

I read something about facets being cached not sure if thats related?


If you override the operator new and use you may meet the same cause as me. the code may be like

#include "yournew" //override new declare .. 
#include "fstream" 
std::fstream f
f.open(...)

because the iostream is template so the new of _Fac_node use your operator new. but when exit, your memory pool may exit before _Fac_tidy, then when ~_Fac_tidy() run,the program crashed.


Memory corruption bugs can (obviously) cause this (and many other kinds) of failure.

Have you tried using valgrind (memcheck) or Rational Purify against this? It will probably report the problem (possibly buried in a whole lot of other information if this would be the first time you ran such a check on your code base. You will still want to devise a minimal 'main' implementation that exhibits the behaviour to run under a memory and bounds checker

$0.02

PS. just in case, memory corruption bugs usually arise

  • by dereferencing stale pointers (after free/delete)
  • by writing beyond the end of an allocated buffer
  • by freeing/deleting previously pointers (mostly a symptom of bad ownership tracking)


The first, accepted, response is correct, but it does not show exactly the reason and hence the way of fixing it. According to the listed part of the call stack, I've encountered into the same problem with VC++8 (MS VS 2005) but in the different case: my CLR DLL caused AV at the same point of the code.

From the listed call stack it is seen that the code of <xdebug> that is normally compiled into msvc*.dll is called but at that moment the _Ptr already has wrong value. Hence, there is some code that either already freed the object under this pointer or set an exit hook to free the uninitialized object.

If _STATIC_CPPLIB was defined, the <xdebug> code could be complied into other modules that are loaded into the application process. Then, one exit procedure of those modules could be called prior to another one in msvcp100d.dll and thus could normally free the facet object. In my case, with _STATIC_CPPLIB defined, both the modules (exe and clr dll) were compiled.

Solution for VC++8,9

Check the final compiler options in the "Command Line" section for the presence /D "_STATIC_CPPLIB". Undefining _STATIC_CPPLIB and recompiling affected modules fixes the AV at program termination.

Note on _STATIC_CPPLIB

For VC++9 _STATIC_CPPLIB, at MSDN, there is the note that

the combination of the _STATIC_CPPLIB preprocessor definition and the /clr or /clr:pure compiler option is not supported.

And there are no mentions on _STATIC_CPPLIB for higher VS versions. For higher VS versions and VS 10 in particular, I suppose that the code dependent on _STATIC_CPPLIB still exists. In the TS's case, if _STATIC_CPPLIB is still used in the compiler options of any TU that includes <string> or other headers including <locale>, this improper combination could lead to AV.


I believe you're experiencing the same bug I did in the MSVC10 runtime. To my understanding, it is caused by the runtime deleting a global facet when a DLL unloads, and then deleting it again when the process ends. If you link everything statically, it shouldn't happen. It also won't happen in MSVC9, either with static or shared linkage.


TLDR; used a custom Allocation class in my code which tracks all memory crated and deleted using new. Since the shutdown function for this class is called before Microsoft's CRT clean up and frees any memory created by this. I simply overrode the CRT code in locale0.cpp in my code, and commented out the loop to free CRT memory. As it's already deleted by my class.

The application is attempting to delete memory it created for wostreambuf* and ostreambuf*., in my instance as part of a lambda function.

It created the memory which got stored in __PURE_APPDOMAIN_GLOBAL static _Fac_node* _Fac_head = nullptr; to be deleted after execution of the program ends. By calling the destructor ~_Fac_tidy_reg_t() from _Fac_tidy_reg_t.

Since in my application i override the new and delete functions and manage the memory myself. The program at the end of execution automatically deletes any memory it used, so when the CRT calls this ~_Fac_tidy_reg_t() destructor the memory is already freed, however not necessarily "nullptrjust marked as unsed. When~_Fac_tidy_reg_t()attempts to cycle through the_Fac_head` the memory is already freed and therefore causes a exception.

To solve this i simply overload ~_Fac_tidy_reg_t() and commented out the code to run the loop to delete the already deleted memory address's.

#if defined(PLATFORM_WINDOWS)

// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

// class locale basic member functions

#include <crtdbg.h>
//#include <internal_shared.h>
#include <xfacet>

// This must be as small as possible, because its contents are
// injected into the msvcprt.lib and msvcprtd.lib import libraries.
// Do not include or define anything else here.
// In particular, basic_string must not be included here.

// This should probably go to a compiler section just after the locks - unfortunately we have per-appdomain
// and per-process variables to initialize
//#pragma warning(disable : 4073)
//#pragma init_seg(lib)

_STD_BEGIN

[[noreturn]] _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _Xbad_alloc();

struct _Fac_node { // node for lazy facet recording
    _Fac_node(_Fac_node* _Nextarg, _Facet_base* _Facptrarg)
        : _Next(_Nextarg), _Facptr(_Facptrarg) {} // construct a node with value

    ~_Fac_node() noexcept { // destroy a facet
        delete _Facptr->_Decref();
    }

#ifdef _DEBUG
    void* operator new(size_t _Size) { // replace operator new
        void* _Ptr = _malloc_dbg(_Size > 0 ? _Size : 1, _CRT_BLOCK, __FILE__, __LINE__);
        if (!_Ptr) {
            _Xbad_alloc();
        }

        return _Ptr;
    }

    void operator delete(void* _Ptr) noexcept { // replace operator delete
        _free_dbg(_Ptr, _CRT_BLOCK);
    }
#endif // _DEBUG

    _Fac_node* _Next;
    _Facet_base* _Facptr;
};

__PURE_APPDOMAIN_GLOBAL static _Fac_node* _Fac_head = nullptr;

* WHILE LOOPS IS COMMENTED OUT */
struct _Fac_tidy_reg_t {
    ~_Fac_tidy_reg_t() noexcept { // destroy lazy facets
        //while (_Fac_head != nullptr) { // destroy a lazy facet node
        //  _Fac_node* nodeptr = _Fac_head;
        //  _Fac_head = nodeptr->_Next;
        //  delete nodeptr;
        //}
    }
};

__PURE_APPDOMAIN_GLOBAL const _Fac_tidy_reg_t _Fac_tidy_reg;

#if defined(_M_CEE)
void __CLRCALL_OR_CDECL _Facet_Register_m(_Facet_base* _This)
#else // defined(_M_CEE)
void __CLRCALL_OR_CDECL _Facet_Register(_Facet_base* _This)
#endif // defined(_M_CEE)
{ // queue up lazy facet for destruction
    _Fac_head = new _Fac_node(_Fac_head, _This);
}

_STD_END

#endif  // PLATFORM_WINDOWS
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜