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

时间:2013-05-08 12:41:42

标签: c# .net garbage-collection buffer-overrun

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

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

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

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

各种其他潜在有用的信息花絮:

  • 提高'吞吐量'可以更快地发生(秒而不是几分钟)
  • 在VS中运行(调试或发布)会阻止它发生(或者至少延迟它比我准备等待的时间更长)
  • 我的C#中没有unsafe,我正在做的唯一“深奥”事情就是将位图(从库中)转换为BitmapSource(如this)。
  • 这些库是为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

2 个答案:

答案 0 :(得分:2)

看起来像是对我的记忆腐败;该库可能使用不安全和/或非托管内存或固定内存......或者它可能没有固定正确的内存位,或者过早取消固定它们?

至于:

  

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

这是因为调试器创建的进程使用不同的堆(即使您在发布模式下运行);使用这个备用堆是处理随机内存损坏时heisenbugs的一个已知来源(我在这一点上没有找到很多来源;我认为它出现在某个地方的Raymond Chen博客上,但我只发现了this

编辑:参考找到了!来自MSDN

  

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

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

答案 1 :(得分:2)

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

在以前版本中程序的可能结束将是致命执行引擎异常,由函数尝试返回并且返回地址损坏时引发的访问冲突触发。现在它可以更快地解决问题。更可靠的是,损坏的返回地址可能意外地指向有效代码。接下来会发生什么,如果是这种情况通常是真正不可诊断的。并且可以利用。

但根本原因是相同的,GC堆被破坏了。