Udostępnij za pośrednictwem


Handling Contract assertions on Windows Phone 8

If you are a fan of System.Diagnostics.Contracts and use them on WP8 you may find a problem: when a contract fails, you get no clue why. Here's how to find out.

Firstly lets start with a trivial repro app, take the default WP8 project, add a using System.Diagnostics.Contracts, add a button, then this code:

         void TestContract(int arg)
        {
            Contract.Assert(arg == 42);
        }
 
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            TestContract(41);
        }

OK, lets F5 this in the Emulator, click the button and the process exits. If you look in the Output window you will see just this:

The program '[2192] TaskHost.exe' has exited with code -2147483645 (0x80000003).

TaskHost.exe is not your exe, its the Silverlight host that all managed apps get run in on the phone. The exit code is instantly recognizable (to crazed folks such as myself at least) as Breakpoint, ie an int 3 (in x86) was hit somewhere. OK so that's obviously not helpful, so switch to the Native debugger (remember the debugger is like Highlander, there can only be one [type]).

Same repro under the native debugger is a bit more useful, you get a MessageBox and the Output window says the same thing:

**** MessageBox invoked, title 'TaskHost.exe - Assertion failed.' ****

  Description: Assertion failed.

********

TaskHost.exe has triggered a breakpoint.

Well at least it stopped in the debugger this time, lets have a look at the callstack:

Not terribly helpful, so lets apply the Microsoft Public Symbols to this callstack:

Much better, and as with asserts, the root cause of this problem is that some code in the CLR wasn't updated for Phone, and tries to show the assert in a MessageBox which doesn't exist, so it dies. Working at Microsoft grants me certain special powers, so I used these (for good, obviously) and ran the repro with full symbols. Turns out if you go to the third frame on the callstack, and enter this into the Watch window, you can get a string containing the managed callstack of the contract failure:

(wchar_t**)($vframe+12)

(This is for x86 ie the Emulator, I have not tried this on an ARM device)

You can then use the totally awesome and brilliant Text Visualizer [you might be able to guess whose idea that feature was] to see the managed callstack that caused the contract failure. Note that there are no line numbers, ah well.

Now you know, somewhat, where the contract failure was, you can go fix it. Don't forget to switch back to the managed debugger when you want to debug that code. We can all hope this this problem (and the assert one) get fixed in the next release of the Phone tools (and it would be super-nice if we could debug both managed and native at the same time, like we have been able to do on the Desktop for a long time).

Please note that I know almost nothing about Contracts, I'm just working in an existing codebase that uses them, and I figured this out while trying to debug that code.

Comments

  • Anonymous
    October 19, 2013
    Maybe not directly related, but Debug.Assert is also broken on Phone 8, I have a workaround class here: www.danielmoth.com/.../DebugAssert-Replacement-For-Phone-And-Store-Apps.aspx

  • Anonymous
    October 21, 2013
    Thanks Daniel, I have not had any problems with managed asserts on Phone, the link in the article is for native asserts on Phone which are broken.