Explain critical bug in Visual Studio 2010 and up, WinForms and WPF
Asked Answered
N

1

7

Try putting the following code inside Load event handler for WinForms or Loaded for WPF.

Dim doc As New XmlDocument
Dim nsmgr As New XmlNamespaceManager(Nothing) 'this line throws an exception

Problem is that exception is not thrown, and stack corruption happens. It may have different side effects, depending on the IDE - see below.

  • Affected IDEs are: 2008, 2010 and 2012 (those I could test). 2010 resets stack state, and returns from sub/handler, like nothing happened (but without proceeding with other statements there). 2012 may warn a user about a failed application and an attempt to run in compatibility mode. Next time after that it runs the same as 2010. 2008 properly throws an exception, but only on default configuration (AnyCPU). Switching platform target to x86 makes the problem reappear in 2008 as well.
  • Affected frameworks are WinForms and WPF. Console apps and ASP.NET seem to work fine. .NET v2.0-4.5.
  • Affected scope is only Load event so far. Putting this code into a button makes it work.
  • Affected build configuration = any. Tried on default Debug and Release.

Why I consider it a bug is because it can leave objects in an unstable state - they did not finish initializing, which is not an expected behavior. What's critical about it is that nobody will know it happened, as it does not throw an exception. Depending on your design, you may end up with incorrect data in your database, which in the worst case may lead to severe consequences.

Does anyone have a good explanation to why this may be happening and if there is a workaround?

Nichy answered 31/10, 2012 at 15:56 Comment(10)
Which framework version? Tried with LinqPAD with 4.0 and throws exception as expected by docsPantin
@Steve: all available, that means .NET 2.0 through 4.5. I updated the question. Thanks for pointing it out.Nichy
The second line of the constructor code of XmlNameSpaceManager is this.xml = nameTable.Add("xml"); where nameTable is the parameter passed to the constructor, and is followed by numerous call of the same kind. So it should throw a NullReferenceException immediately. Very strange behavior indeed.Pantin
@Steve: exactly, that's what it should do, and what it does on vs2008. Thanks for looking into this. Perhaps, you could also test it in Visual Studio to see if you can reproduce? Let's make sure it's not just my framework get corrupted somehow. Anyone else who can reproduce same problem?Nichy
Perhaps this explain the mistery #4934458Pantin
Checked the code in C#, VS2010 (on Win7 x64) NullReferenceException is only raised if you specifically catch "Common Language Exceptions" in the Debug -> Exceptions menu. Otherwise, as you stated, no exception is raised and any code after the second line does not run...Nora
@Steve: yes, this is it. Problem is when running on x64 and your target is x86, this is how it works (i.e. does not work). x64 and AnyCPU works fine, same as x64 / x64. Please post as an answer to be accepted. I have still to find a solid workaround.Nichy
@Blachshma: if you catch all thrown exceptions, you would also stop on Try...Catch which seem to handle this just fine inside the Load handler. Would be nice if it blew up only on unhandled exceptions.Nichy
How is this a "critical" bug? It seems pretty obscure.Couvade
@JohnSaunders: it can leave objects in unstable state, because they did not finish initializing. What's critical about it is that nobody will know it happened, as it does not throw an exception. You may end up with incorrect data in your database, find out your bank account balance is 0 one day, or your insurance premium is suddenly a million dollars per month. :)Nichy
P
2

The problem is caused by the wow64 emulation layer that comes into play when you target x86 platform on a x64 OS.
It swallows exceptions in the code that is responsible to fire the Load event.
Thus the debugger doesn't see the exception and cannot step in to handle the situation.
This article seems to document well what's happening there,

This previous answer from Hans Passant (to which goes all the credits and upvotes) explains possible workarounds.
My preferite one is to move everything out of Form_Load event and put the problematic code in the form constructor. (Of course I don't know if it is applicable in your case)

Pantin answered 31/10, 2012 at 22:33 Comment(2)
I have lots of code in Form_Loads of different forms, which historically ended up there. Now I have a good reason to reconsider my design. Thanks for digging it up.Nichy
I also re-tested on VS 2008 and the problem persists. Why I did not catch it before is because VS 2008 by default creates an application targeted for AnyCPU, unlike 2010 and 2012, where default is x86. Having put VS 2008 to x86, I got the same issue, so it's completely unrelated to the choice of IDE.Nichy

© 2022 - 2024 — McMap. All rights reserved.