WinCE 6.0 R3下.Net CF框架代码出现奇怪异常
在我们的 .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。堆栈跟踪显示:
at ArrayList.InternalSetCapacity(Int32 value, Boolean updateVersion) at ArrayList.EnsureCapacity(Int32 min) at ArrayList.Add(Object value) at String.Split(Char[] separator) at AddParm(String str)
这是在工作线程上发生的。
我确实在 Main 中使用 AppDomain.CurrentDomain.UnhandledException 注册了一个处理程序,但它也没有捕获异常。
不幸的是,出现的 WinCE 错误对话框没有说明错误类型或给出错误消息,只是指出它位于 mscoree3_5.dll 和堆栈跟踪中。
我们创建由 AddParm 解析的值,我认为 AddParm 具有足够的防御性,它可以在 Split 调用之前捕获任何潜在的问题。由于 AddParm 的调用方式,它永远不会用空字符串调用。尽管我不相信 AddParm 可以用无效的东西来调用,但包装调用的 Try...Catch 应该始终捕获异常,但事实并非如此。
同样,我们也看到了这样的未捕获错误:
A native exception has occurred on BbCore.exe At RuntimeType.InternalGetField(rt…) At RuntimeType.InternalGetField(rt…) At SRSupport.GetString() At SRSupport.GetString() At IPAddress.Parse(String ipString)
这是今天早上的完整堆栈跟踪:
At CurrentSystemTimeZone.GetDaylightChanges(Int32 year) At CurrentSystemTimeZone.GetUtcOffsetFromUniversalTime(DateTime time, Boolean& isAmbiguousLocalDst) At CurrentSystemTimeZone.ToLocalTime(DateTime time) At DateTime.ToLocalTime() At DateTime.get_Now() At MainLoop.timer1_Tick(Object sender, EventArgs e) At Timer._WnProc(WM wm, Int32 wParam, Int32 lParam) At ApplicationThreadContext._InternalContextMessages(WM wm, Int32 wParam, Int32 lParam) At NativeMethods.GetMessage(MSG& lpMsg, IntPtr hWnd, UInt32 wMsgFilterMin, UInt32 wMsgFilterMax) At Application2.Pump() At Application2.RunMessageLoop(Boolean showForm) At Application2.Run(Form mainForm, Boolean runAsSingletonApp, Boolean displayMainForm) At 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。
In our .Net CF app we are getting weird errors from parts of the code that shouldn't be having problems. For instance, the following code:
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);
}
}
The routine that calls AddParm() wraps the call in a Try...Catch block, catching all Exception types.
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);
}
}
I just got a core unhandled exception listing the faulting module as mscoree3_5.dll. The stack trace shows:
at ArrayList.InternalSetCapacity(Int32 value, Boolean updateVersion) at ArrayList.EnsureCapacity(Int32 min) at ArrayList.Add(Object value) at String.Split(Char[] separator) at AddParm(String str)
This is happening on a worker thread.
I did register a handler with AppDomain.CurrentDomain.UnhandledException in Main but it doesn't catch the exception either.
Unfortunately the WinCE error dialog that comes up does not state the type of error or give an error message, just that it was in mscoree3_5.dll and the stack trace.
We create the values that get parsed by AddParm and I think AddParm is defensive enough that it would catch any potential problems before the Split call. Due to the way AddParm is called it wouldn't ever be called with a null string. Even though I don't believe AddParm could ever be called with something that is invalid, the Try...Catch wrapping the call should always catch the exception but it doesn't.
Similarly we have also seen uncaught errors like this:
A native exception has occurred on BbCore.exe At RuntimeType.InternalGetField(rt…) At RuntimeType.InternalGetField(rt…) At SRSupport.GetString() At SRSupport.GetString() At IPAddress.Parse(String ipString)
Here's a full stack trace from one this morning:
At CurrentSystemTimeZone.GetDaylightChanges(Int32 year) At CurrentSystemTimeZone.GetUtcOffsetFromUniversalTime(DateTime time, Boolean& isAmbiguousLocalDst) At CurrentSystemTimeZone.ToLocalTime(DateTime time) At DateTime.ToLocalTime() At DateTime.get_Now() At MainLoop.timer1_Tick(Object sender, EventArgs e) At Timer._WnProc(WM wm, Int32 wParam, Int32 lParam) At ApplicationThreadContext._InternalContextMessages(WM wm, Int32 wParam, Int32 lParam) At NativeMethods.GetMessage(MSG& lpMsg, IntPtr hWnd, UInt32 wMsgFilterMin, UInt32 wMsgFilterMax) At Application2.Pump() At Application2.RunMessageLoop(Boolean showForm) At Application2.Run(Form mainForm, Boolean runAsSingletonApp, Boolean displayMainForm) At Startup.Main()
The Application2 references are due to the use of OpenNetCF.Windows.Forms.dll. I have never seen a crash in that part of the code, it's basically random.
That's another case where IPAddress.Parse is called from within a Try...Catch that catches all Exception types. In that case I believe it was possible for Parse to be called with an empty string but I don't understand why it showed up as an unhandled exception and didn't even get caught by our unhandled exception handler but instead got caught by the WindowsCE exception handler and caused the whole app to crash.
It seems like these are more common since we updated to WinCE 6 R3 platform builder from R2. I'm not sure if they ever happened under R2 but they certainly were less frequent. Even now they don't always happen - I can't reliably reproduce them.
Any ideas? Why would core parts of the framework throw errors that don't get caught by Try..Catch?
Extra info: It appears I left out a critical piece of information. The ExceptionCode is listed as 0x80000002 which appears to be a native out of memory exception. According to the garbage collector our app rarely uses more than 1MB of memory. According to coredll.dll's GlobalMemoryStatus the typical memory load for the system is about 29% (41MB free out of 57MB). Are there any good utilities out there that might be able to monitor and log the total system memory use over time? I'm starting to wonder if the techniques I'm using to measure memory use aren't as accurate as I thought. Using OpenNetCF.ToolHelp.ProcessEntry.GetProcesses() shows our process using about 3.6MB and NK.exe using about 2.5 MB.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
结果发现这是本机代码中的缓冲区溢出错误。 C# 代码调用一个方法并传递一个包含 8 个元素的字节数组。 C++ 代码填充 6 个字节,然后用零覆盖另外 6 个字节。这个方法被调用了很多次,每次都会用零覆盖 4 个字节的内存。哎哟!
这解释了完全奇怪的错误,可能是覆盖了内存中 .Net 框架的位。
必须注意托管代码和非托管代码之间的交互。对我来说幸运的是,有问题的代码不是我的。
(不确定我是否应该接受我自己的答案作为答案,因为没有人可以在不查看我们的代码库的情况下回答这个问题。同样,我不应该将 JaredPar 的答案标记为“答案”,因为问题是内存损坏,而不是真正的问题我想我还是会发布这个,因为也许其他人也会有类似的情况,也许他们会研究与本机代码的交互:如果您认为这是最好的,请随意删除此线程。)
Turned out it was a buffer overrun error in native code. the C# code was calling into a method and passing a byte array with 8 elements. The C++ code was filling 6 bytes then overwriting another 6 with zeroes. This method got called quite a lot and every time it was overwriting 4 bytes of memory with zeroes. Doh!
That explains the utterly strange errors, probably was overwriting bits of the .Net framework in memory.
Gotta watch out for those interactions between managed and unmanaged code. Fortunately for me, the code in question wasn't mine.
(Not sure if I should accept my own answer as the answer since no one could have answered this without looking at our code base. Likewise I shouldn't mark JaredPar's answer as "the answer" since the problem was memory corruption, not really a native exception. I guess I'll post this anyway since maybe someone else will have a similar situation and maybe they'll look into interactions with native code. Admins: feel free to delete this thread if you think that's best.)
我认为你的第二个跟踪上的消息是最具启发性的
看来,这是一个本机异常,而不是导致您的产品崩溃的托管异常。一般来说,托管代码无法捕获本机异常。在某些情况下这是可能的,但一般来说本机异常是致命的。
您可以尝试对 SEH 异常使用 catch 块,看看是否有效。
但一般来说,如果本机代码引发应用程序不稳定并且应该崩溃。
I think the message on your second trace is the most instructive
It appears that it's a native exception not a managed exception that is taking down your product. Native exceptions are as a general rule not catchable by managed code. It is possible in certain cases but generally speaking native exceptions are fatal.
You can try to use the catch block for SEH exceptions and see if that works.
But in general if the native code is throwing your application is unstable and it should crash.
我刚刚在我的应用程序的新版本中遇到了这个错误。
尝试了几件事,最后,我删除了表单图标中的256x256和64x64图像,这些图像在这个版本中被替换,并且它起作用了。
I just run into this error in a new version of my application.
Tried several things, in the last, I removed the 256x256 and 64x64 images in the form icon which are replaced in this version, and it worked.