4

目前正在测试建立在 C++ 库之上的 C# (.Net 4.5) 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
4

2 回答 2

4

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

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

但根本原因是一样的,GC 堆损坏了。

于 2013-05-08T12:56:03.590 回答
3

对我来说似乎是内存损坏;该库可能正在使用不安全和/或非托管内存或固定内存......或者它可能没有固定正确的内存位,或者过早地取消固定它们?

至于:

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

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

编辑:找到参考!来自MSDN

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

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

于 2013-05-08T12:51:38.323 回答