Windows Phone 8.1 C# app: critical crash (Executio

2019-06-28 08:16发布

问题:

Imagine the following struct type:

public struct Token : IDictionary<string, Token>
{
    public readonly object Value;
    public Token(string str) { Value = str; }
    public Token(IDictionary<string, Token> dict) { Value = dict; }

    /* IDictionary<string, Token> implementation is here */
}

Don't ask me anything about what it does. Implementation doesn't matter, you can throw NotImplementedException in all methods/properties. It is placed in separate portable class library.

Then imagine the usage of this struct:

var token = new Token("111");
var kvp = new KeyValuePair<string, Token>("aaa", token);
var val = kvp.Value.Value;
var t = val.GetType(); // XXX

This code works perfectly almost everywhere:

  • in desktop app / windows service (haven't tried 'metro' apps)
  • on WinPhone 8.1 emulator in any mode (release, debug, with or without debugger)
  • on real WinPhone 8.1 device (tried on Lumia 625) in debug mode

But when I run this code on real WP 8.1 device (Lumia 625, latest updates) in RELEASE mode, then I get ExecutionEngineException exception at line XXX with message An unhandled exception of type 'System.ExecutionEngineException' occurred in Unknown Module. This exception can't be caught and doesn't contain any details - app just crashes.

Is this a bug? Or known limitations of WinPhone? Why it works on emulator? And all this strange "conditions" are important:

  • Token must be struct, not class
  • It must implement IDictionary<K,V>, not any other interface (tried IList<Token>, ICollection)
  • It must be placed in separate portable class library. If I move it in WP 8.1 project - it works fine
  • Instance of Token must be placed inside KeyValuePair<K,V>. If you do just token.Value.GetType() - it works fine

I created VS 2013 solution to reproduce this situation. It can be downloaded here.

回答1:

I created the error report at Microsoft Connect couple months ago and have been waiting for response but it doesn't look that somebody in Microsoft is interested in fixing this bug.

By the way I created a more simple repro:

public struct Token : IDictionary<string, Token>
{
    /* IDictionary<string, Token> implementation is here */
}
public static class Test
{
    //[MethodImpl(MethodImplOptions.NoOptimization)]
    public static void Method()
    {
        var dict = new Dictionary<string, Token> { { "qwe", new Token() } };
        var arr = dict.ToArray(); // XXX        
    }
}

Implementation of IDictionary<string, Token> doesn't matter, the exception occurs at line XXX. And they (Token definition and usage) can be located in one assembly.

I also noticed that adding the MethodImpl(MethodImplOptions.NoOptimization) attribute to a method that uses Token fixes the problem, so even considering that I'm not a .NET guru I'm 99% sure that it is a bug in compiler (C#, MDIL, NGEN, whatever) for ARM that is somehow related to optimizations.