垃圾收集期间缓冲区溢出:心理调试请求

本文关键字:调试 请求 溢出 缓冲区 | 更新日期: 2023-09-27 18:12:54

目前正在测试c#。. Net 4.5)基于c++库构建的WPF应用程序(托管的,我相信,不是我写的)。由于各种(实际)原因,它运行在服务器上(安装了VS2012,是的,讨厌)。

程序连接到相机(通过库)并显示它接收到的图像帧。

奇怪的是,我得到缓冲区溢出(缓冲区溢出我可以理解)。在垃圾收集期间!

A buffer overrun has occurred in App.exe which has corrupted the program's internal state.

各种其他可能有用的花絮信息:

  • 提高"吞吐量"使其更快发生(秒而不是分钟)
  • 在VS中运行(调试或发布)完全阻止它发生(或至少延迟它比我准备等待的时间更长)
  • 在我的c#中没有unsafe,我正在做的唯一"深奥"的事情是将位图(从库)转换为BitmapSource(像这样)。
  • 这些库是为x86编译的,exe也是。

调用堆栈,每次都一样:

vcr110_clr0400.dll!__crt_debugger_hook ()   Unknown
clr.dll!___raise_securityfailure () Unknown
clr.dll!___report_gsfailure ()  Unknown
clr.dll!CrawlFrame::SetCurGSCookie(unsigned long *) Unknown
clr.dll!StackFrameIterator::Init(class Thread *,class Frame *,struct _REGDISPLAY *,unsigned int)    Unknown
clr.dll!Thread::StackWalkFramesEx(struct _REGDISPLAY *,enum StackWalkAction (*)(class CrawlFrame *,void *),void *,unsigned int,class Frame *)   Unknown
clr.dll!Thread::StackWalkFrames(enum StackWalkAction (*)(class CrawlFrame *,void *),void *,unsigned int,class Frame *)  Unknown
clr.dll!CNameSpace::GcScanRoots(void (*)(class Object * *,struct ScanContext *,unsigned long),int,int,struct ScanContext *,class GCHeap *)  Unknown
clr.dll!WKS::gc_heap::mark_phase(int,int)   Unknown
clr.dll!WKS::gc_heap::gc1(void) Unknown
clr.dll!WKS::gc_heap::garbage_collect(int)  Unknown
clr.dll!WKS::GCHeap::GarbageCollectGeneration(unsigned int,enum WKS::gc_reason) Unknown
clr.dll!WKS::GCHeap::GarbageCollectTry(int,int,int) Unknown
clr.dll!WKS::GCHeap::GarbageCollect(int,int,int)    Unknown
clr.dll!GCInterface::Collect(int,int)   Unknown
mscorlib.ni.dll!6dcd33e5()  Unknown
[Frames below may be incorrect and/or missing, no symbols loaded for mscorlib.ni.dll]   
mscorlib.ni.dll!6dcd33e5()  Unknown
064afa73()  Unknown
clr.dll!MethodTable::FastBox(void * *)  Unknown
clr.dll!MethodTable::CallFinalizer(class Object *)  Unknown
clr.dll!SVR::CallFinalizer(class Object *)  Unknown
clr.dll!SVR::CallFinalizer(class Object *)  Unknown
clr.dll!SVR::CallFinalizer(class Object *)  Unknown
clr.dll!WKS::GCHeap::FinalizerThreadWorker(void *)  Unknown
clr.dll!Thread::DoExtraWorkForFinalizer(void)   Unknown
clr.dll!Thread::DoExtraWorkForFinalizer(void)   Unknown
clr.dll!Thread::DoExtraWorkForFinalizer(void)   Unknown
clr.dll!WKS::GCHeap::FinalizerThreadStart(void *)   Unknown
clr.dll!Thread::intermediateThreadProc(void *)  Unknown
kernel32.dll!@BaseThreadInitThunk@12 () Unknown
ntdll.dll!___RtlUserThreadStart@8 ()    Unknown
ntdll.dll!__RtlUserThreadStart@8 () Unknown

垃圾收集期间缓冲区溢出:心理调试请求

与v2 CLR不同,v4 CLR是在启用Microsoft安全CRT扩展的情况下构建的。其中包括检查,在函数退出时,"堆栈金丝雀"没有被覆盖。由/GS编译器选项启用。

在以前的版本中,程序可能会以致命执行引擎异常(Fatal Execution Engine Exception)结束,当函数试图返回且返回地址损坏时,可能会引发访问冲突,从而触发该异常。现在它能更快地发现问题。更可靠的是,损坏的返回地址可能意外指向有效代码。如果是这种情况,接下来会发生什么通常是无法诊断的。和可利用的。

但是根本原因是一样的,GC堆被破坏了

看起来像是内存损坏;库可能使用不安全和/或非托管内存或固定内存…或者是没有固定正确的记忆片段,或者过早地解除它们?

:

在VS中运行(调试或发布)完全阻止它发生(或至少延迟它比我准备等待的时间更长)

这是因为由调试器创建的进程使用不同的堆(即使你在发布模式下运行);在处理随机内存损坏时,使用这个备用堆是已知的heisenbug的来源(然而,我没有找到很多关于这一点的来源;我以为是在Raymond Chen的博客上,但我只找到了这个)

编辑:找到参考!从MSDN:

调试器创建的进程(也称为衍生进程)的行为与调试器不创建的进程略有不同。
与使用标准堆API不同,调试器创建的进程使用特殊的调试堆。通过使用_NO_DEBUG_HEAP环境变量或-hd命令行选项,可以强制生成的进程使用标准堆而不是调试堆。

我最好的猜测是:c++库破坏了一些内存。GC来了,发现堆损坏了,崩溃了。或者:c++库确实忘记了固定它用作图像缓冲区的内存。GC来了,移动内存。c++库不知道,写入一个现在无效的指针,导致损坏。GC又来了,开始处理已经损坏的内存,崩溃