_DebugHeapDelete 终止时访问冲突

发布于 2024-10-30 13:24:02 字数 1960 浏览 6 评论 0原文

我在主程序末尾遇到了奇怪的访问冲突,我很难找到其原因。

关闭我的应用程序时,我收到以下访问冲突:

xdebug

        // TEMPLATE 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**
        }
    }

堆栈跟踪:

>   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

有人对可能导致此问题的原因有任何想法吗?

我读到一些有关缓存方面的内容,不确定这是否相关?

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 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

荭秂 2024-11-06 13:24:02

如果您覆盖 new 运算符并使用您可能会遇到与我相同的原因。
代码可能是这样的

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

,因为 iostream 是模板,所以 _Fac_node 的 new 使用你的运算符 new。但是当退出时,你的内存池可能会在_Fac_tidy之前退出,然后当~_Fac_tidy()运行时,程序崩溃了。

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.

梦中楼上月下 2024-11-06 13:24:02

内存损坏错误可能(显然)导致这种(以及许多其他类型)故障。

您是否尝试过使用 valgrind (memcheck) 或 Rational Purify 来解决这个问题?它可能会报告问题(如果这是您第一次对代码库运行此类检查,则可能会隐藏在大量其他信息中)。您仍然想要设计一个最小的“主” ' 表现出在内存和边界检查器下运行的行为

$0.02

PS,以防万一,内存损坏错误通常是

  • 来取消引用陈旧指针(释放/删除后)而
  • 超出已分配缓冲区的末尾
  • 通过先前释放/删除而 引起的。指针(主要是所有权跟踪不良的症状)

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)
哆啦不做梦 2024-11-06 13:24:02

第一个被接受的响应是正确的,但它没有准确地显示原因以及修复它的方法。根据调用堆栈的列出部分,我在 VC++8 (MS VS 2005) 中遇到了同样的问题,但情况不同:我的 CLR DLL 在代码的同一点导致了 AV。

从列出的调用堆栈中可以看出,正常情况下编译成 msvc*.dll 的 代码被调用,但此时 _Ptr 已经出现错误价值。因此,有一些代码要么已经释放了该指针下的对象,要么设置了退出挂钩来释放未初始化的对象。

如果_STATIC_CPPLIB< /a> 被定义后, 代码可以被编译到加载到应用程序进程中的其他模块中。然后,这些模块的一个退出过程可以在 msvcp100d.dll 中的另一个退出过程之前被调用,因此可以正常释放构面对象。就我而言,定义了 _STATIC_CPPLIB 后,两个模块(exe 和 clr dll)都已编译。

Solution for VC++8,9

检查“命令行”部分中的最终编译器选项是否存在 /D "_STATIC_CPPLIB"。取消定义 _STATIC_CPPLIB 并重新编译受影响的模块可修复程序终止时的 AV。

Note on _STATIC_CPPLIB

对于 VC++9 _STATIC_CPPLIB< /code>,在 MSDN 上,有这样的注释:

_STATIC_CPPLIB预处理器定义和
不支持 /clr/clr:pure 编译器选项。

并且没有提及更高 VS 版本的 _STATIC_CPPLIB
对于更高的 VS 版本,特别是 VS 10,我认为依赖于 _STATIC_CPPLIB 的代码仍然存在。在 TS 的情况下,如果 _STATIC_CPPLIB 仍然在包含 或其他包含 的标头的 TU 的编译器选项中使用code>,这种不正确的组合可能会导致 AV。

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.

念三年u 2024-11-06 13:24:02

我相信您也遇到了同样的bug 我在 MSVC10 运行时中遇到了这个问题。据我了解,这是由于运行时在 DLL 卸载时删除全局 Facet,然后在进程结束时再次删除它造成的。如果您静态链接所有内容,则不会发生这种情况。在 MSVC9 中也不会发生这种情况,无论是静态链接还是共享链接。

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.

极度宠爱 2024-11-06 13:24:02

太长了;在我的代码中使用了自定义分配类,该类跟踪使用 new 创建和删除的所有内存。由于此类的关闭函数是在 Microsoft 的 CRT 清理并释放由此创建的任何内存之前调用的。我只是在代码中覆盖了 locale0.cpp 中的 CRT 代码,并注释掉了循环以释放 CRT 内存。因为它已经被我的班级删除了。

应用程序正在尝试删除它为wostreambuf* 和ostreambuf*创建的内存,在我的实例中作为lambda 函数的一部分。

它创建了存储在 __PURE_APPDOMAIN_GLOBAL static _Fac_node* _Fac_head = nullptr; 中的内存,并在程序执行结束后将其删除。通过从 _Fac_tidy_reg_t 调用析构函数 ~_Fac_tidy_reg_t()

因为在我的应用程序中,我重写了 new 和 delete 函数并自己管理内存。程序在执行结束时会自动删除它使用的任何内存,因此当 CRT 调用此~_Fac_tidy_reg_t()析构函数时,内存已经被释放,但不一定“ nullptr刚刚标记为未使用。当~_Fac_tidy_reg_t()尝试循环_Fac_head`时,内存已被释放,因此会导致异常。

要解决此问题,我只需重载 ~_Fac_tidy_reg_t() 并注释掉运行循环以删除删除内存地址的代码。

#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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文