1

如果帖子太长,我很抱歉,但如果有人至少指出粗体标题,我会很高兴,并指出我正确的方向。我这几天遇到这个问题,但无法在网上找到答案。这些是我到目前为止发现的东西。

1.“访问冲突”异常崩溃了我的托管应用程序

我的 C# WinForms 应用程序有时会在 Windows 窗体 TabControl 中选择 TabPage 时以“访问冲突”异常(“尝试读取或写入受保护的内存”)关闭。从堆栈跟踪(在 Application.Run 周围尝试/捕获)我可以看到异常发生在System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg),在内部调用UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)

-- 消息:试图读取或写入受保护的内存。
   这通常表明其他内存已损坏。
-  堆栈跟踪:
   在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(味精和味精)
   在 System.Windows.Forms.Application.ComponentManager
      .System.Windows.Forms.UnsafeNativeMethods
      .IMsoComponentManager.FPushMessageLoop
      (Int32 dwComponentID,Int32 原因,Int32 pvLoopData)
   在 System.Windows.Forms.Application.ThreadContext
      .RunMessageLoopInner(Int32 原因,ApplicationContext 上下文)
   在 System.Windows.Forms.Application.ThreadContext
      .RunMessageLoop(Int32 原因,ApplicationContext 上下文)
   在 System.Windows.Forms.Application.Run(ApplicationContext 上下文)
   在 MyApp.Program.Main()

2. 故障模块似乎是一个 COM 对象(ChartFX Client Server 6.2)

使用 WinDbg(加载了 SoS),我在 ChartFX.ClientServer.Core.dll(这是我们正在使用的 COM 图表组件)内部的非托管端捕获了它:

(ca84.c98c):访问冲突 - 代码 c0000005(第一次机会)
在任何异常处理之前报告第一次机会异常。
可以预期并处理此异常。
eax=00000000 ebx=06e67c38 ecx=06e67c38 edx=000018c6 esi=06e7df30 edi=317a9e80
eip=31666110 esp=0015e040 ebp=0015e08c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
ChartFX_ClientServer_Core!Ordinal5507+0x97b7:
31666110 8a404d mov al,byte ptr [eax+4Dh] ds:0023:0000004d=??

[编辑:]我也无法从 WinDbg 获得未管理的堆栈详细信息(它说“堆栈展开信息不可用”):

0:000> kP
ChildEBP RetAddr  
警告:堆栈展开信息不可用。以下框架可能是错误的。
0015e08c 3166288b ChartFX_ClientServer_Core!Ordinal5507+0x97b7
0015e394 3165a921 ChartFX_ClientServer_Core!Ordinal5507+0x5f32
0015e480 31678685 ChartFX_ClientServer_Core!Ordinal5496+0x26a
0015e568 3167bef4 ChartFX_ClientServer_Core!Ordinal5492+0x975
0015e668 316a356b ChartFX_ClientServer_Core!Ordinal5492+0x41e4
0015e77c 31709496 ChartFX_ClientServer_Core!Ordinal443+0x5745
0015e7d0 31707f70 ChartFX_ClientServer_Core!Ordinal2584+0x3cdc
0015e7f8 3170817d ChartFX_ClientServer_Core!Ordinal2584+0x27b6
0015e81c 3162fd76 ChartFX_ClientServer_Core!Ordinal2584+0x29c3
0015e86c 7719f8d2 ChartFX_ClientServer_Core!Ordinal899+0x6b6
0015e898 7719f794 USER32!GetMessageW+0x93
0015e910 771a06f6 USER32!GetWindowLongW+0x115
0015e940 771a069c USER32!CallWindowProcW+0x75
0015e960 747fcef4 USER32!CallWindowProcW+0x1b
0015e97c 747fd073 comctl32!Ordinal377+0x5c
0015e9e0 747fd027 comctl32!DefSubclassProc+0x92
0015ea04 747fd4e6 comctl32!DefSubclassProc+0x46
0015ea20 747fd073 comctl32!DefSubclassProc+0x505
0015ea84 747fd118 comctl32!DefSubclassProc+0x92
0015eae4 7719f8d2 comctl32!DefSubclassProc+0x137

3、Bug 不易复现(虽然一般5分钟内就可以引发)

我在几个 TabPages 中有几个 Chart 实例,这通常发生在我切换选项卡时。我仍然不知道如何重现它,除了在它发生之前切换这些选项卡几分钟,所以我不能使用我们的源代码管理来可靠地找到没有这个问题的构建。我通过 VS 设计器自动创建的托管 AxChart 包装类(从 AxHost 派生)访问图表。

4. 我的下一步应该是什么?

如果有人能指出我应该采取的下一步行动来找到真正的原因,我将不胜感激。实验(删除和返回代码)并没有多大好处,因为我不知道如何重现它,所以每次迭代都需要大量时间才能说服自己该错误仍然存​​在。

我发现人们经常建议“切换编译器优化”之类的东西,但由于异常不是确定性地抛出的,我不想简单地重新排列一些字节并希望它永远不会返回。

4

3 回答 3

2

通过在整个代码中添加大量日志跟踪,我设法注意到在某些情况下,图表的一个属性会变成 Double.NaN。在我得到那个之后,应用程序总是在下一次图表重绘期间崩溃。通过处理图表的 PrePaint 和 PostPaint 事件(幸运的是它有这些事件),我确认崩溃发生在这两个事件之间。

特别是,仅当我在第一次绘制图表之前设置图表的缩放比例(自上次更新以来的第一次)时才会发生这种情况。我设法以不同的方式做到了,从那以后它就没有崩溃过。

我对这个“解决方案”不是很满意,因为它显然是一些内部问题,在它实际崩溃之前无法准确检测到,我可能只是这样隐藏它。但我必须暂时保留它,否则我会浪费太多时间。

[更新]

成功复制错误

我做了一个快速测试应用程序,在实际绘制之前,我设置了一些图表的属性两次,应用程序立即崩溃。我已经向 Software FX 报告了这个错误,但没有得到答复。这不是我在使用此控件时遇到的第一个恼人的错误,但是对于我们的下一个版本,我们将切换到他们的托管 (.Net) 版本,因此我们至少会有 Reflector 来找出如何解决这些错误。

总之谢谢大家!

于 2009-03-19T13:29:26.803 回答
1

它看起来很像一个线程安全问题。
我建议您首先阅读控件的文档,专门寻找线程安全的提及。COM 组件通常使用的线程模型与(微不足道的).NET 用法不同——而且通常不兼容。

于 2009-03-15T21:16:15.083 回答
0

前一阵子有一个。我们的例子是一个 PInvoke 调用: OpenPrinter(string port);

我们的问题是托管代码发送了:“LPT1:”,但非托管代码声明了一个 byte[1024] 数组并从字符串地址开始读取 1024 个字节。这将在分配的字符串(“LPT1:”)的范围之外读取,并且偶尔会进入未分配给应用程序的内存,从而导致此间歇性 AccessViolationException。

我们通过将调用更改为: OpenPrinter(int length, string port) 来解决此问题,因此非托管代码可以声明一个长度正确的字节数组。

ctacke 的这篇文章也有一些关于试图找出可能导致此问题的好东西。

于 2009-03-15T17:08:45.443 回答