3

在我们的 .Net CF 应用程序中,我们从不应该有问题的部分代码中得到奇怪的错误。例如,下面的代码:

public void AddParm(string str)
{
    string[]        pair = str.Split('=');
    string          key = pair[0].Trim();
    string          value = pair.Length > 1 ? pair[1] : "";
    if (key.Length > 0)
    {
        if (_parmTable.ContainsKey(key))
            _parmTable[key] = value;
        else
            _parmTable.Add(key, value);
    }
}

调用 AddParm() 的例程将调用包装在 Try...Catch 块中,捕获所有异常类型。

public void Unpack(string txn)
{
    try
    {
        // split out strings like: "EVENTLABEL:x=1,y=2,z=3"
        char chEvent = ':';
        char chSeparator = ',';

        _parmTable = new Hashtable();

        int iEvent = txn.IndexOf(chEvent);

        if (iEvent == -1)
            _eventLabel = txn;
        else
        {
            _eventLabel = txn.Substring(0, iEvent);

            string parms = txn.Substring(iEvent + 1).TrimEnd('\n');
            string[] items = parms.Split(chSeparator);

            if (items.Length <= 0)
                AddParm(parms);
            else
                foreach (string item in items)
                    AddParm(item);
        }
    }
    catch (Exception ex)
    {
        AppLog.logException(string.Format("UnpackedTask.Unpack: Error parsing '{0}'", txn), ex);
    }
}

我刚刚得到一个核心未处理异常,将故障模块列为 mscoree3_5.dll。堆栈跟踪显示:

在 ArrayList.InternalSetCapacity(Int32 值,布尔 updateVersion)
在 ArrayList.EnsureCapacity(Int32 分钟)
在 ArrayList.Add(对象值)
在 String.Split(Char[] 分隔符)
在 AddParm(字符串 str)

这发生在工作线程上。

我确实在 Main 中使用 AppDomain.CurrentDomain.UnhandledException 注册了一个处理程序,但它也没有捕获异常。

不幸的是,出现的 WinCE 错误对话框没有说明错误类型或给出错误消息,只是它在 mscoree3_5.dll 和堆栈跟踪中。

我们创建了由 AddParm 解析的值,我认为 AddParm 具有足够的防御性,它可以在 Split 调用之前捕获任何潜在的问题。由于调用 AddParm 的方式,它永远不会用空字符串调用。即使我不相信 AddParm 可以用无效的东西调用,包装调用的 Try...Catch 应该总是捕获异常,但它没有。

同样,我们也看到了像这样的未捕获错误:

BbCore.exe 发生本机异常

在 RuntimeType.InternalGetField(rt…)
在 RuntimeType.InternalGetField(rt…)
在 SRSupport.GetString()
在 SRSupport.GetString()
在 IPAddress.Parse(String ipString)

这是今天早上的完整堆栈跟踪:

在 CurrentSystemTimeZone.GetDaylightChanges(Int32 年)
At CurrentSystemTimeZone.GetUtcOffsetFromUniversalTime(DateTime time, Boolean& isAmbiguousLocalDst)
在 CurrentSystemTimeZone.ToLocalTime(DateTime 时间)
在 DateTime.ToLocalTime()
在 DateTime.get_Now()
在 MainLoop.timer1_Tick(Object sender, EventArgs e)
在 Timer._WnProc(WM wm, Int32 wParam, Int32 lParam)
在 ApplicationThreadContext._InternalContextMessages(WM wm, Int32 wParam, Int32 lParam)
在 NativeMethods.GetMessage(MSG& lpMsg,IntPtr hWnd,UInt32 wMsgFilterMin,UInt32 wMsgFilterMax)
在 Application2.Pump()
在 Application2.RunMessageLoop(Boolean showForm)
在 Application2.Run(Form mainForm, Boolean runAsSingletonApp, Boolean displayMainForm)
在 Startup.Main()

Application2 引用是由于使用了 OpenNetCF.Windows.Forms.dll。我从未见过代码的那部分崩溃,它基本上是随机的。

这是从捕获所有异常类型的 Try...Catch 中调用 IPAddress.Parse 的另一种情况。在那种情况下,我相信 Parse 可以使用空字符串调用,但我不明白为什么它显示为未处理的异常,甚至没有被我们的未处理异常处理程序捕获,而是被 WindowsCE 捕获异常处理程序并导致整个应用程序崩溃。

自从我们从 R2 更新到 WinCE 6 R3 平台构建器以来,这些似乎更常见。我不确定它们是否曾经在 R2 下发生过,但它们肯定不那么频繁。即使现在它们并不总是发生 - 我无法可靠地复制它们。

有任何想法吗?为什么框架的核心部分会抛出 Try..Catch 无法捕获的错误?

额外信息: 看来我遗漏了一条关键信息。ExceptionCode 列为 0x80000002,这似乎是本机内存不足异常。根据垃圾收集器的说法,我们的应用程序很少使用超过 1MB 的内存。根据 coredll.dll 的 GlobalMemoryStatus,系统的典型内存负载约为 29%(57MB 中有 41MB 空闲)。是否有任何好的实用程序可以监控和记录一段时间内的总系统内存使用情况?我开始怀疑我用来测量内存使用的技术是否没有我想象的那么准确。使用 OpenNetCF.ToolHelp.ProcessEntry.GetProcesses() 显示我们的进程使用了​​大约 3.6MB,NK.exe 使用了大约 2.5MB。

4

3 回答 3

3

原来这是本机代码中的缓冲区溢出错误。C# 代码调用了一个方法并传递了一个包含 8 个元素的字节数组。C++ 代码填充了 6 个字节,然后用零覆盖了另外 6 个字节。这个方法被调用了很多次,每次它用零覆盖 4 个字节的内存。嗬!

这解释了完全奇怪的错误,可能是在内存中覆盖了 .Net 框架的一部分。

必须注意托管代码和非托管代码之间的交互。对我来说幸运的是,有问题的代码不是我的。

(不确定我是否应该接受我自己的答案作为答案,因为没有人可以在不查看我们的代码库的情况下回答这个问题。同样,我不应该将 JaredPar 的答案标记为“答案”,因为问题是内存损坏,而不是真正的本机异常。我想我还是会发布这个,因为也许其他人会有类似的情况,也许他们会研究与本机代码的交互。管理员:如果你认为这是最好的,请随时删除这个线程。)

于 2010-02-22T23:18:37.797 回答
1

我认为你第二次追踪的信息是最有启发性的

BbCore.exe 发生本机异常

看起来它是一个本机异常而不是托管异常,正在取消您的产品。本机异常通常是托管代码无法捕获的。在某些情况下是可能的,但一般来说原生异常是致命的。

您可以尝试对 SEH 异常使用 catch 块,看看是否有效。

try { 
  ...
} catch { 

}

但一般来说,如果本机代码抛出您的应用程序是不稳定的,它应该会崩溃。

于 2010-02-11T18:41:13.510 回答
0

我刚刚在我的应用程序的新版本中遇到了这个错误。尝试了几件事,最后,我删除了在此版本中替换的表单图标中的 256x256 和 64x64 图像,并且它起作用了。

于 2014-05-21T08:43:10.703 回答